Merge "Obfuscate any phone numbers that pass through the event log." into jb-mr2-dev
diff --git a/Android.mk b/Android.mk
index 43791c7..5bf4d41 100644
--- a/Android.mk
+++ b/Android.mk
@@ -69,7 +69,6 @@
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
-	core/java/android/app/INotificationListener.aidl \
 	core/java/android/app/INotificationManager.aidl \
 	core/java/android/app/IProcessObserver.aidl \
 	core/java/android/app/ISearchManager.aidl \
@@ -125,6 +124,8 @@
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	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/usb/IUsbManager.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -148,6 +149,7 @@
 	core/java/android/os/IUpdateLock.aidl \
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
+	core/java/android/service/notification/INotificationListener.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
@@ -180,6 +182,7 @@
 	core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
+	core/java/com/android/internal/backup/IObbBackupService.aidl \
 	core/java/com/android/internal/policy/IFaceLockCallback.aidl \
 	core/java/com/android/internal/policy/IFaceLockInterface.aidl \
 	core/java/com/android/internal/os/IDropBoxManagerService.aidl \
@@ -194,10 +197,10 @@
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
 	core/java/com/android/internal/view/IInputMethod.aidl \
-	core/java/com/android/internal/view/IInputMethodCallback.aidl \
 	core/java/com/android/internal/view/IInputMethodClient.aidl \
 	core/java/com/android/internal/view/IInputMethodManager.aidl \
 	core/java/com/android/internal/view/IInputMethodSession.aidl \
+	core/java/com/android/internal/view/IInputSessionCallback.aidl \
 	core/java/com/android/internal/widget/ILockSettings.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
 	core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
@@ -206,10 +209,12 @@
 	location/java/android/location/ICountryDetector.aidl \
 	location/java/android/location/ICountryListener.aidl \
 	location/java/android/location/IGeocodeProvider.aidl \
+	location/java/android/location/IGeofenceProvider.aidl \
 	location/java/android/location/IGpsStatusListener.aidl \
 	location/java/android/location/IGpsStatusProvider.aidl \
 	location/java/android/location/ILocationListener.aidl \
 	location/java/android/location/ILocationManager.aidl \
+	location/java/android/location/IGpsGeofenceHardware.aidl \
 	location/java/android/location/INetInitiatedListener.aidl \
 	location/java/com/android/internal/location/ILocationProvider.aidl \
 	media/java/android/media/IAudioService.aidl \
@@ -305,7 +310,6 @@
 	frameworks/base/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputContext.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputMethod.aidl \
-	frameworks/base/core/java/com/android/internal/view/IInputMethodCallback.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputMethodClient.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputMethodManager.aidl \
 	frameworks/base/core/java/com/android/internal/view/IInputMethodSession.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b87fa48..4debdc2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -156,6 +156,10 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/librtp_jni.so)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/SmsRawData.*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodCallback.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodSession.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodCallback.*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index 2e1dcf6..7451a93 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22,6 +22,7 @@
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
+    field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
@@ -68,6 +69,7 @@
     field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
+    field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
     field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
@@ -339,8 +341,10 @@
     field public static final int checkedTextViewStyle = 16843720; // 0x10103c8
     field public static final int childDivider = 16843025; // 0x1010111
     field public static final int childIndicator = 16843020; // 0x101010c
+    field public static final int childIndicatorEnd = 16843732; // 0x10103d4
     field public static final int childIndicatorLeft = 16843023; // 0x101010f
     field public static final int childIndicatorRight = 16843024; // 0x1010110
+    field public static final int childIndicatorStart = 16843731; // 0x10103d3
     field public static final int choiceMode = 16843051; // 0x101012b
     field public static final int clearTaskOnLaunch = 16842773; // 0x1010015
     field public static final int clickable = 16842981; // 0x10100e5
@@ -574,8 +578,10 @@
     field public static final int indeterminateDuration = 16843069; // 0x101013d
     field public static final int indeterminateOnly = 16843066; // 0x101013a
     field public static final int indeterminateProgressStyle = 16843544; // 0x1010318
+    field public static final int indicatorEnd = 16843730; // 0x10103d2
     field public static final int indicatorLeft = 16843021; // 0x101010d
     field public static final int indicatorRight = 16843022; // 0x101010e
+    field public static final int indicatorStart = 16843729; // 0x10103d1
     field public static final int inflatedId = 16842995; // 0x10100f3
     field public static final int initOrder = 16842778; // 0x101001a
     field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
@@ -846,6 +852,7 @@
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
     field public static final int required = 16843406; // 0x101028e
+    field public static final int requiredForAllUsers = 16843728; // 0x10103d0
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -853,6 +860,7 @@
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
+    field public static final int restrictedAccountType = 16843733; // 0x10103d5
     field public static final int right = 16843183; // 0x10101af
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -2134,8 +2142,10 @@
   public abstract class AbstractAccountAuthenticator {
     ctor public AbstractAccountAuthenticator(android.content.Context);
     method public abstract android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
+    method public android.os.Bundle addAccountFromCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
+    method public android.os.Bundle getAccountCredentialsForCloning(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public android.os.Bundle getAccountRemovalAllowed(android.accounts.AccountAuthenticatorResponse, android.accounts.Account) throws android.accounts.NetworkErrorException;
     method public abstract android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
     method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
@@ -2202,6 +2212,7 @@
     field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
     field public static final java.lang.String AUTHENTICATOR_META_DATA_NAME = "android.accounts.AccountAuthenticator";
     field public static final int ERROR_CODE_BAD_ARGUMENTS = 7; // 0x7
+    field public static final int ERROR_CODE_BAD_AUTHENTICATION = 9; // 0x9
     field public static final int ERROR_CODE_BAD_REQUEST = 8; // 0x8
     field public static final int ERROR_CODE_CANCELED = 4; // 0x4
     field public static final int ERROR_CODE_INVALID_RESPONSE = 5; // 0x5
@@ -2443,6 +2454,7 @@
     method public static android.animation.ObjectAnimator ofObject(java.lang.Object, java.lang.String, android.animation.TypeEvaluator, java.lang.Object...);
     method public static android.animation.ObjectAnimator ofObject(T, android.util.Property<T, V>, android.animation.TypeEvaluator<V>, V...);
     method public static android.animation.ObjectAnimator ofPropertyValuesHolder(java.lang.Object, android.animation.PropertyValuesHolder...);
+    method public void setAutoCancel(boolean);
     method public void setProperty(android.util.Property);
     method public void setPropertyName(java.lang.String);
   }
@@ -2467,6 +2479,11 @@
     method public void setPropertyName(java.lang.String);
   }
 
+  public class RectEvaluator implements android.animation.TypeEvaluator {
+    ctor public RectEvaluator();
+    method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
+  }
+
   public class TimeAnimator extends android.animation.ValueAnimator {
     ctor public TimeAnimator();
     method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
@@ -2579,6 +2596,10 @@
     method public abstract void setDisplayShowHomeEnabled(boolean);
     method public abstract void setDisplayShowTitleEnabled(boolean);
     method public abstract void setDisplayUseLogoEnabled(boolean);
+    method public void setHomeActionContentDescription(java.lang.CharSequence);
+    method public void setHomeActionContentDescription(int);
+    method public void setHomeAsUpIndicator(android.graphics.drawable.Drawable);
+    method public void setHomeAsUpIndicator(int);
     method public void setHomeButtonEnabled(boolean);
     method public abstract void setIcon(int);
     method public abstract void setIcon(android.graphics.drawable.Drawable);
@@ -4329,6 +4350,7 @@
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
+    method public boolean isDeviceOwner(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
@@ -4603,8 +4625,13 @@
     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);
     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";
@@ -4635,6 +4662,14 @@
     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 class BluetoothAssignedNumbers {
     field public static final int ACCEL_SEMICONDUCTOR = 74; // 0x4a
     field public static final int ALCATEL = 36; // 0x24
@@ -4827,6 +4862,7 @@
   }
 
   public final class BluetoothDevice implements android.os.Parcelable {
+    method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
     method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
@@ -4835,6 +4871,7 @@
     method public android.bluetooth.BluetoothClass getBluetoothClass();
     method public int getBondState();
     method public java.lang.String getName();
+    method public int getType();
     method public android.os.ParcelUuid[] getUuids();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
@@ -4849,6 +4886,10 @@
     field public static final int BOND_BONDING = 11; // 0xb
     field public static final int BOND_NONE = 10; // 0xa
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int DEVICE_TYPE_CLASSIC = 1; // 0x1
+    field public static final int DEVICE_TYPE_DUAL = 3; // 0x3
+    field public static final int DEVICE_TYPE_LE = 2; // 0x2
+    field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int ERROR = -2147483648; // 0x80000000
     field public static final java.lang.String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
     field public static final java.lang.String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
@@ -4859,6 +4900,162 @@
     field public static final java.lang.String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
   }
 
+  public final class BluetoothGatt implements android.bluetooth.BluetoothProfile {
+    method public void abortReliableWrite(android.bluetooth.BluetoothDevice);
+    method public boolean beginReliableWrite();
+    method public void close();
+    method public boolean connect();
+    method public void disconnect();
+    method public boolean discoverServices();
+    method public boolean executeReliableWrite();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public android.bluetooth.BluetoothDevice getDevice();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
+    method public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+    method public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public boolean readRemoteRssi();
+    method public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
+    method public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+    method public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    field public static final int GATT_FAILURE = 0; // 0x0
+    field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5
+    field public static final int GATT_INSUFFICIENT_ENCRYPTION = 15; // 0xf
+    field public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 13; // 0xd
+    field public static final int GATT_INVALID_OFFSET = 7; // 0x7
+    field public static final int GATT_READ_NOT_PERMITTED = 2; // 0x2
+    field public static final int GATT_REQUEST_NOT_SUPPORTED = 6; // 0x6
+    field public static final int GATT_SUCCESS = 0; // 0x0
+    field public static final int GATT_WRITE_NOT_PERMITTED = 3; // 0x3
+  }
+
+  public abstract class BluetoothGattCallback {
+    ctor public BluetoothGattCallback();
+    method public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic);
+    method public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
+    method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
+    method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int);
+    method public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
+    method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
+    method public void onReadRemoteRssi(android.bluetooth.BluetoothGatt, int, int);
+    method public void onReliableWriteCompleted(android.bluetooth.BluetoothGatt, int);
+    method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
+  }
+
+  public class BluetoothGattCharacteristic {
+    ctor public BluetoothGattCharacteristic(java.util.UUID, int, int);
+    method public boolean addDescriptor(android.bluetooth.BluetoothGattDescriptor);
+    method public android.bluetooth.BluetoothGattDescriptor getDescriptor(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattDescriptor> getDescriptors();
+    method public java.lang.Float getFloatValue(int, int);
+    method public int getInstanceId();
+    method public java.lang.Integer getIntValue(int, int);
+    method public int getPermissions();
+    method public int getProperties();
+    method public android.bluetooth.BluetoothGattService getService();
+    method public java.lang.String getStringValue(int);
+    method public java.util.UUID getUuid();
+    method public byte[] getValue();
+    method public int getWriteType();
+    method public boolean setValue(byte[]);
+    method public boolean setValue(int, int, int);
+    method public boolean setValue(int, int, int, int);
+    method public boolean setValue(java.lang.String);
+    method public void setWriteType(int);
+    field public static final int FORMAT_FLOAT = 52; // 0x34
+    field public static final int FORMAT_SFLOAT = 50; // 0x32
+    field public static final int FORMAT_SINT16 = 34; // 0x22
+    field public static final int FORMAT_SINT32 = 36; // 0x24
+    field public static final int FORMAT_SINT8 = 33; // 0x21
+    field public static final int FORMAT_UINT16 = 18; // 0x12
+    field public static final int FORMAT_UINT32 = 20; // 0x14
+    field public static final int FORMAT_UINT8 = 17; // 0x11
+    field public static final int PERMISSION_READ = 1; // 0x1
+    field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
+    field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
+    field public static final int PERMISSION_WRITE = 16; // 0x10
+    field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
+    field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
+    field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
+    field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
+    field public static final int PROPERTY_BROADCAST = 1; // 0x1
+    field public static final int PROPERTY_EXTENDED_PROPS = 128; // 0x80
+    field public static final int PROPERTY_INDICATE = 32; // 0x20
+    field public static final int PROPERTY_NOTIFY = 16; // 0x10
+    field public static final int PROPERTY_READ = 2; // 0x2
+    field public static final int PROPERTY_SIGNED_WRITE = 64; // 0x40
+    field public static final int PROPERTY_WRITE = 8; // 0x8
+    field public static final int PROPERTY_WRITE_NO_RESPONSE = 4; // 0x4
+    field public static final int WRITE_TYPE_DEFAULT = 2; // 0x2
+    field public static final int WRITE_TYPE_NO_RESPONSE = 1; // 0x1
+    field public static final int WRITE_TYPE_SIGNED = 4; // 0x4
+    field protected java.util.List mDescriptors;
+  }
+
+  public class BluetoothGattDescriptor {
+    ctor public BluetoothGattDescriptor(java.util.UUID, int);
+    method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic();
+    method public int getPermissions();
+    method public java.util.UUID getUuid();
+    method public byte[] getValue();
+    method public boolean setValue(byte[]);
+    field public static final byte[] DISABLE_NOTIFICATION_VALUE;
+    field public static final byte[] ENABLE_INDICATION_VALUE;
+    field public static final byte[] ENABLE_NOTIFICATION_VALUE;
+    field public static final int PERMISSION_READ = 1; // 0x1
+    field public static final int PERMISSION_READ_ENCRYPTED = 2; // 0x2
+    field public static final int PERMISSION_READ_ENCRYPTED_MITM = 4; // 0x4
+    field public static final int PERMISSION_WRITE = 16; // 0x10
+    field public static final int PERMISSION_WRITE_ENCRYPTED = 32; // 0x20
+    field public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 64; // 0x40
+    field public static final int PERMISSION_WRITE_SIGNED = 128; // 0x80
+    field public static final int PERMISSION_WRITE_SIGNED_MITM = 256; // 0x100
+  }
+
+  public final class BluetoothGattServer implements android.bluetooth.BluetoothProfile {
+    method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public void cancelConnection(android.bluetooth.BluetoothDevice);
+    method public void clearServices();
+    method public boolean connect(android.bluetooth.BluetoothDevice, boolean);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
+    method public boolean notifyCharacteristicChanged(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothGattCharacteristic, boolean);
+    method public boolean removeService(android.bluetooth.BluetoothGattService);
+    method public boolean sendResponse(android.bluetooth.BluetoothDevice, int, int, int, byte[]);
+  }
+
+  public abstract class BluetoothGattServerCallback {
+    ctor public BluetoothGattServerCallback();
+    method public void onCharacteristicReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattCharacteristic);
+    method public void onCharacteristicWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattCharacteristic, boolean, boolean, int, byte[]);
+    method public void onConnectionStateChange(android.bluetooth.BluetoothDevice, int, int);
+    method public void onDescriptorReadRequest(android.bluetooth.BluetoothDevice, int, int, android.bluetooth.BluetoothGattDescriptor);
+    method public void onDescriptorWriteRequest(android.bluetooth.BluetoothDevice, int, android.bluetooth.BluetoothGattDescriptor, boolean, boolean, int, byte[]);
+    method public void onExecuteWrite(android.bluetooth.BluetoothDevice, int, boolean);
+    method public void onServiceAdded(int, android.bluetooth.BluetoothGattService);
+  }
+
+  public class BluetoothGattService {
+    ctor public BluetoothGattService(java.util.UUID, int);
+    method public boolean addCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
+    method public boolean addService(android.bluetooth.BluetoothGattService);
+    method public android.bluetooth.BluetoothGattCharacteristic getCharacteristic(java.util.UUID);
+    method public java.util.List<android.bluetooth.BluetoothGattCharacteristic> getCharacteristics();
+    method public java.util.List<android.bluetooth.BluetoothGattService> getIncludedServices();
+    method public int getInstanceId();
+    method public int getType();
+    method public java.util.UUID getUuid();
+    field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0
+    field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1
+    field protected java.util.List mCharacteristics;
+    field protected java.util.List mIncludedServices;
+  }
+
   public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
     method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -4921,6 +5118,14 @@
     method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
   }
 
+  public final class BluetoothManager {
+    method public android.bluetooth.BluetoothAdapter getAdapter();
+    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
+    method public int getConnectionState(android.bluetooth.BluetoothDevice, int);
+    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int, int[]);
+    method public android.bluetooth.BluetoothGattServer openGattServer(android.content.Context, android.bluetooth.BluetoothGattServerCallback);
+  }
+
   public abstract interface BluetoothProfile {
     method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
     method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
@@ -4928,6 +5133,8 @@
     field public static final int A2DP = 2; // 0x2
     field public static final java.lang.String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE";
     field public static final java.lang.String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
+    field public static final int GATT = 7; // 0x7
+    field public static final int GATT_SERVER = 8; // 0x8
     field public static final int HEADSET = 1; // 0x1
     field public static final int HEALTH = 3; // 0x3
     field public static final int STATE_CONNECTED = 2; // 0x2
@@ -5402,6 +5609,7 @@
     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();
@@ -5484,6 +5692,7 @@
     field public static final int BIND_IMPORTANT = 64; // 0x40
     field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
     field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
+    field public static final java.lang.String BLUETOOTH_SERVICE = "bluetooth";
     field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
     field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
     field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -5845,6 +6054,7 @@
     field public static final java.lang.String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
     field public static final java.lang.String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
     field public static final java.lang.String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";
+    field public static final java.lang.String ACTION_GET_RESTRICTION_ENTRIES = "android.intent.action.GET_RESTRICTION_ENTRIES";
     field public static final java.lang.String ACTION_GTALK_SERVICE_CONNECTED = "android.intent.action.GTALK_CONNECTED";
     field public static final java.lang.String ACTION_GTALK_SERVICE_DISCONNECTED = "android.intent.action.GTALK_DISCONNECTED";
     field public static final java.lang.String ACTION_HEADSET_PLUG = "android.intent.action.HEADSET_PLUG";
@@ -5917,7 +6127,6 @@
     field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
     field public static final java.lang.String ACTION_USER_PRESENT = "android.intent.action.USER_PRESENT";
     field public static final java.lang.String ACTION_VIEW = "android.intent.action.VIEW";
-    field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
     field public static final java.lang.String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
     field public static final deprecated java.lang.String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
     field public static final java.lang.String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
@@ -5987,6 +6196,8 @@
     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_INTENT = "android.intent.extra.restrictions_intent";
     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";
@@ -6158,6 +6369,7 @@
     ctor public Loader(android.content.Context);
     method public void abandon();
     method public boolean cancelLoad();
+    method public void commitContentChanged();
     method public java.lang.String dataToString(D);
     method public void deliverCancellation();
     method public void deliverResult(D);
@@ -6178,6 +6390,7 @@
     method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
     method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
     method public void reset();
+    method public void rollbackContentChanged();
     method public final void startLoading();
     method public void stopLoading();
     method public boolean takeContentChanged();
@@ -6227,6 +6440,40 @@
     ctor public ReceiverCallNotAllowedException(java.lang.String);
   }
 
+  public class RestrictionEntry implements android.os.Parcelable {
+    ctor public RestrictionEntry(java.lang.String, java.lang.String);
+    ctor public RestrictionEntry(java.lang.String, boolean);
+    ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
+    ctor public RestrictionEntry(android.os.Parcel);
+    method public int describeContents();
+    method public java.lang.String[] getAllSelectedStrings();
+    method public java.lang.String[] getChoiceEntries();
+    method public java.lang.String[] getChoiceValues();
+    method public java.lang.String getDescription();
+    method public java.lang.String getKey();
+    method public boolean getSelectedState();
+    method public java.lang.String getSelectedString();
+    method public java.lang.String getTitle();
+    method public int getType();
+    method public void setAllSelectedStrings(java.lang.String[]);
+    method public void setChoiceEntries(java.lang.String[]);
+    method public void setChoiceEntries(android.content.Context, int);
+    method public void setChoiceValues(java.lang.String[]);
+    method public void setChoiceValues(android.content.Context, int);
+    method public void setDescription(java.lang.String);
+    method public void setSelectedState(boolean);
+    method public void setSelectedString(java.lang.String);
+    method public void setTitle(java.lang.String);
+    method public void setType(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int TYPE_BOOLEAN = 1; // 0x1
+    field public static final int TYPE_CHOICE = 2; // 0x2
+    field public static final int TYPE_CHOICE_LEVEL = 3; // 0x3
+    field public static final int TYPE_MULTI_SELECT = 4; // 0x4
+    field public static final int TYPE_NULL = 0; // 0x0
+  }
+
   public class SearchRecentSuggestionsProvider extends android.content.ContentProvider {
     ctor public SearchRecentSuggestionsProvider();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
@@ -6617,6 +6864,7 @@
     method public abstract boolean addPermission(android.content.pm.PermissionInfo);
     method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
     method public abstract deprecated void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+    method public android.content.Intent buildPermissionRequestIntent(java.lang.String...);
     method public abstract java.lang.String[] canonicalToCurrentPackageNames(java.lang.String[]);
     method public abstract int checkPermission(java.lang.String, java.lang.String);
     method public abstract int checkSignatures(java.lang.String, java.lang.String);
@@ -6691,6 +6939,7 @@
     field public static final int DONT_KILL_APP = 1; // 0x1
     field public static final java.lang.String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID";
     field public static final java.lang.String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
+    field public static final java.lang.String FEATURE_APP_WIDGETS = "android.software.app_widgets";
     field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
     field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
     field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
@@ -6701,6 +6950,8 @@
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
+    field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
+    field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
     field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
     field public static final java.lang.String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
@@ -10193,6 +10444,43 @@
 
 }
 
+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 pauseGeofence(int, int);
+    method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+    method public boolean removeGeofence(int, int);
+    method public boolean resumeGeofence(int, int, int);
+    method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+    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
+    field public static final int GEOFENCE_ERROR_INVALID_TRANSITION = 4; // 0x4
+    field public static final int GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 1; // 0x1
+    field public static final int GEOFENCE_EXITED = 2; // 0x2
+    field public static final int GEOFENCE_FAILURE = 5; // 0x5
+    field public static final int GEOFENCE_SUCCESS = 0; // 0x0
+    field public static final int GEOFENCE_UNCERTAIN = 4; // 0x4
+    field public static final int MONITORING_TYPE_GPS_HARDWARE = 0; // 0x0
+    field public static final int MONITOR_CURRENTLY_AVAILABLE = 0; // 0x0
+    field public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1; // 0x1
+    field public static final int MONITOR_UNSUPPORTED = 2; // 0x2
+  }
+
+  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 onMonitoringSystemChange(int, boolean, android.location.Location);
+  }
+
+}
+
 package android.hardware.usb {
 
   public class UsbAccessory implements android.os.Parcelable {
@@ -10262,10 +10550,12 @@
   }
 
   public class UsbDeviceConnection {
-    method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
+    method public deprecated 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 int controlTransfer(int, int, int, int, byte[], int, int);
+    method public deprecated 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();
     method public java.lang.String getSerial();
@@ -10921,6 +11211,7 @@
     method public void playSoundEffect(int);
     method public void playSoundEffect(int, float);
     method public void registerMediaButtonEventReceiver(android.content.ComponentName);
+    method public void registerMediaButtonEventReceiver(android.app.PendingIntent);
     method public void registerRemoteControlClient(android.media.RemoteControlClient);
     method public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public deprecated void setBluetoothA2dpOn(boolean);
@@ -10941,6 +11232,7 @@
     method public void stopBluetoothSco();
     method public void unloadSoundEffects();
     method public void unregisterMediaButtonEventReceiver(android.content.ComponentName);
+    method public void unregisterMediaButtonEventReceiver(android.app.PendingIntent);
     method public void unregisterRemoteControlClient(android.media.RemoteControlClient);
     field public static final java.lang.String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
     field public static final deprecated java.lang.String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
@@ -11265,6 +11557,7 @@
     method public static android.media.MediaCodec createByCodecName(java.lang.String);
     method public static android.media.MediaCodec createDecoderByType(java.lang.String);
     method public static android.media.MediaCodec createEncoderByType(java.lang.String);
+    method public final android.view.Surface createInputSurface();
     method public final int dequeueInputBuffer(long);
     method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
     method public final void flush();
@@ -11278,6 +11571,7 @@
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
     method public final void setVideoScalingMode(int);
+    method public final void signalEndOfInputStream();
     method public final void start();
     method public final void stop();
     field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
@@ -11357,6 +11651,7 @@
     field public static final int COLOR_FormatRawBayer10bit = 31; // 0x1f
     field public static final int COLOR_FormatRawBayer8bit = 30; // 0x1e
     field public static final int COLOR_FormatRawBayer8bitcompressed = 32; // 0x20
+    field public static final int COLOR_FormatSurface = 2130708361; // 0x7f000789
     field public static final int COLOR_FormatYCbYCr = 25; // 0x19
     field public static final int COLOR_FormatYCrYCb = 26; // 0x1a
     field public static final int COLOR_FormatYUV411PackedPlanar = 18; // 0x12
@@ -11579,6 +11874,21 @@
     field public static final int OPTION_PREVIOUS_SYNC = 0; // 0x0
   }
 
+  public final class MediaMuxer {
+    ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
+    method public int addTrack(android.media.MediaFormat);
+    method public void release();
+    method public void setOrientationHint(int);
+    method public void start();
+    method public void stop();
+    method public void writeSampleData(int, java.nio.ByteBuffer, android.media.MediaCodec.BufferInfo);
+    field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
+  }
+
+  public static final class MediaMuxer.OutputFormat {
+    field public static final int MUXER_OUTPUT_MPEG_4 = 0; // 0x0
+  }
+
   public class MediaPlayer {
     ctor public MediaPlayer();
     method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -11792,6 +12102,7 @@
     method public android.media.MediaRouter.UserRouteInfo createUserRoute(android.media.MediaRouter.RouteCategory);
     method public android.media.MediaRouter.RouteCategory getCategoryAt(int);
     method public int getCategoryCount();
+    method public android.media.MediaRouter.RouteInfo getDefaultRoute();
     method public android.media.MediaRouter.RouteInfo getRouteAt(int);
     method public int getRouteCount();
     method public android.media.MediaRouter.RouteInfo getSelectedRoute(int);
@@ -12182,6 +12493,14 @@
     field public static final int CONTENT_TYPE_VOICE = 3; // 0x3
     field public static final java.lang.String EFFECT_AUXILIARY = "Auxiliary";
     field public static final java.lang.String EFFECT_INSERT = "Insert";
+    field public static final java.util.UUID EFFECT_TYPE_AEC;
+    field public static final java.util.UUID EFFECT_TYPE_AGC;
+    field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST;
+    field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB;
+    field public static final java.util.UUID EFFECT_TYPE_EQUALIZER;
+    field public static final java.util.UUID EFFECT_TYPE_NS;
+    field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB;
+    field public static final java.util.UUID EFFECT_TYPE_VIRTUALIZER;
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -4; // 0xfffffffc
     field public static final int ERROR_DEAD_OBJECT = -7; // 0xfffffff9
@@ -13561,6 +13880,7 @@
     method public deprecated android.net.DhcpInfo getDhcpInfo();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
+    method public boolean isScanningAlwaysAvailable();
     method public boolean isWifiEnabled();
     method public boolean pingSupplicant();
     method public boolean reassociate();
@@ -13571,6 +13891,7 @@
     method public boolean startScan();
     method public int updateNetwork(android.net.wifi.WifiConfiguration);
     field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
+    field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
     field public static final int ERROR_AUTHENTICATING = 1; // 0x1
     field public static final java.lang.String EXTRA_BSSID = "bssid";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
@@ -14111,6 +14432,7 @@
     method public static int eglGetError();
     method public static boolean eglInitialize(android.opengl.EGLDisplay, int[], int, int[], int);
     method public static boolean eglMakeCurrent(android.opengl.EGLDisplay, android.opengl.EGLSurface, android.opengl.EGLSurface, android.opengl.EGLContext);
+    method public static boolean eglPresentationTimeANDROID(android.opengl.EGLDisplay, android.opengl.EGLSurface, long);
     method public static int eglQueryAPI();
     method public static boolean eglQueryContext(android.opengl.EGLDisplay, android.opengl.EGLContext, int, int[], int);
     method public static java.lang.String eglQueryString(android.opengl.EGLDisplay, int);
@@ -16243,7 +16565,7 @@
     method public abstract android.os.IBinder asBinder();
   }
 
-  public class Looper {
+  public final class Looper {
     method public void dump(android.util.Printer, java.lang.String);
     method public static android.os.Looper getMainLooper();
     method public java.lang.Thread getThread();
@@ -16298,9 +16620,9 @@
     field public int what;
   }
 
-  public class MessageQueue {
-    method public final void addIdleHandler(android.os.MessageQueue.IdleHandler);
-    method public final void removeIdleHandler(android.os.MessageQueue.IdleHandler);
+  public final class MessageQueue {
+    method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
   }
 
   public static abstract interface MessageQueue.IdleHandler {
@@ -16551,7 +16873,6 @@
     method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final deprecated boolean supportsProcesses();
-    field public static final int BLUETOOTH_GID = 2000; // 0x7d0
     field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
     field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
     field public static final int PHONE_UID = 1001; // 0x3e9
@@ -16674,6 +16995,7 @@
     method public android.os.StrictMode.VmPolicy build();
     method public android.os.StrictMode.VmPolicy.Builder detectActivityLeaks();
     method public android.os.StrictMode.VmPolicy.Builder detectAll();
+    method public android.os.StrictMode.VmPolicy.Builder detectFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
@@ -16718,13 +17040,28 @@
   }
 
   public class UserManager {
+    method public static synchronized android.os.UserManager get(android.content.Context);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
     method public java.lang.String getUserName();
+    method public android.os.Bundle getUserRestrictions();
+    method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean isUserAGoat();
+    method public boolean isUserRestricted();
     method public boolean isUserRunning(android.os.UserHandle);
     method public boolean isUserRunningOrStopping(android.os.UserHandle);
+    method public void setUserRestriction(java.lang.String, boolean);
+    method public void setUserRestrictions(android.os.Bundle);
+    method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
+    field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+    field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi";
+    field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
+    field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
+    field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+    field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
+    field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
+    field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
   }
 
   public abstract class Vibrator {
@@ -17857,6 +18194,13 @@
     field public static final java.lang.String TYPE = "data2";
   }
 
+  public static final class ContactsContract.CommonDataKinds.Contactables implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
+    ctor public ContactsContract.CommonDataKinds.Contactables();
+    field public static final android.net.Uri CONTENT_FILTER_URI;
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
+  }
+
   public static final class ContactsContract.CommonDataKinds.Email implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
     method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
     method public static final int getTypeLabelResource(int);
@@ -18135,6 +18479,7 @@
   }
 
   protected static abstract interface ContactsContract.ContactsColumns {
+    field public static final java.lang.String CONTACT_LAST_UPDATED_TIMESTAMP = "contact_last_updated_timestamp";
     field public static final java.lang.String DISPLAY_NAME = "display_name";
     field public static final java.lang.String HAS_PHONE_NUMBER = "has_phone_number";
     field public static final java.lang.String IN_VISIBLE_GROUP = "in_visible_group";
@@ -18150,6 +18495,7 @@
     method public static android.net.Uri getContactLookupUri(android.content.ContentResolver, android.net.Uri);
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/data";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
   }
 
   protected static abstract interface ContactsContract.DataColumns {
@@ -18180,7 +18526,7 @@
     field public static final java.lang.String SYNC4 = "data_sync4";
   }
 
-  protected static abstract interface ContactsContract.DataColumnsWithJoins implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.StatusColumns {
+  protected static abstract interface ContactsContract.DataColumnsWithJoins implements android.provider.BaseColumns android.provider.ContactsContract.ContactNameColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.DataUsageStatColumns android.provider.ContactsContract.RawContactsColumns android.provider.ContactsContract.StatusColumns {
   }
 
   public static final class ContactsContract.DataUsageFeedback {
@@ -18193,6 +18539,21 @@
     field public static final java.lang.String USAGE_TYPE_SHORT_TEXT = "short_text";
   }
 
+  protected static abstract interface ContactsContract.DataUsageStatColumns {
+    field public static final java.lang.String LAST_TIME_USED = "last_time_used";
+    field public static final java.lang.String TIMES_USED = "times_used";
+  }
+
+  public static final class ContactsContract.DeletedContacts implements android.provider.ContactsContract.DeletedContactsColumns {
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final long DAYS_KEPT_MILLISECONDS = 2592000000L; // 0x9a7ec800L
+  }
+
+  protected static abstract interface ContactsContract.DeletedContactsColumns {
+    field public static final java.lang.String CONTACT_DELETED_TIMESTAMP = "contact_deleted_timestamp";
+    field public static final java.lang.String CONTACT_ID = "contact_id";
+  }
+
   public static final class ContactsContract.Directory implements android.provider.BaseColumns {
     method public static void notifyDirectoryChange(android.content.ContentResolver);
     field public static final java.lang.String ACCOUNT_NAME = "accountName";
@@ -18272,6 +18633,7 @@
   public static final class ContactsContract.Intents {
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
+    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String INVITE_CONTACT = "com.android.contacts.action.INVITE_CONTACT";
@@ -19336,8 +19698,7 @@
     method public int getUsage();
     method public void ioReceive();
     method public void ioSend();
-    method public synchronized void resize(int);
-    method public synchronized void resize(int, int);
+    method public deprecated synchronized void resize(int);
     method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
     method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
     method public void setSurface(android.view.Surface);
@@ -19610,29 +19971,6 @@
     method public void skip(int);
   }
 
-  public deprecated class FileA3D extends android.renderscript.BaseObj {
-    method public static deprecated android.renderscript.FileA3D createFromAsset(android.renderscript.RenderScript, android.content.res.AssetManager, java.lang.String);
-    method public static deprecated android.renderscript.FileA3D createFromFile(android.renderscript.RenderScript, java.lang.String);
-    method public static deprecated android.renderscript.FileA3D createFromFile(android.renderscript.RenderScript, java.io.File);
-    method public static deprecated android.renderscript.FileA3D createFromResource(android.renderscript.RenderScript, android.content.res.Resources, int);
-    method public deprecated android.renderscript.FileA3D.IndexEntry getIndexEntry(int);
-    method public deprecated int getIndexEntryCount();
-  }
-
-  public static final deprecated class FileA3D.EntryType extends java.lang.Enum {
-    method public static android.renderscript.FileA3D.EntryType valueOf(java.lang.String);
-    method public static final android.renderscript.FileA3D.EntryType[] values();
-    enum_constant public static final deprecated android.renderscript.FileA3D.EntryType MESH;
-    enum_constant public static final deprecated android.renderscript.FileA3D.EntryType UNKNOWN;
-  }
-
-  public static deprecated class FileA3D.IndexEntry {
-    method public deprecated android.renderscript.FileA3D.EntryType getEntryType();
-    method public deprecated android.renderscript.Mesh getMesh();
-    method public deprecated java.lang.String getName();
-    method public deprecated android.renderscript.BaseObj getObject();
-  }
-
   public class Float2 {
     ctor public Float2();
     ctor public Float2(float, float);
@@ -19657,23 +19995,6 @@
     field public float z;
   }
 
-  public deprecated class Font extends android.renderscript.BaseObj {
-    method public static deprecated android.renderscript.Font create(android.renderscript.RenderScript, android.content.res.Resources, java.lang.String, android.renderscript.Font.Style, float);
-    method public static deprecated android.renderscript.Font createFromAsset(android.renderscript.RenderScript, android.content.res.Resources, java.lang.String, float);
-    method public static deprecated android.renderscript.Font createFromFile(android.renderscript.RenderScript, android.content.res.Resources, java.lang.String, float);
-    method public static deprecated android.renderscript.Font createFromFile(android.renderscript.RenderScript, android.content.res.Resources, java.io.File, float);
-    method public static deprecated android.renderscript.Font createFromResource(android.renderscript.RenderScript, android.content.res.Resources, int, float);
-  }
-
-  public static final deprecated class Font.Style extends java.lang.Enum {
-    method public static android.renderscript.Font.Style valueOf(java.lang.String);
-    method public static final android.renderscript.Font.Style[] values();
-    enum_constant public static final deprecated android.renderscript.Font.Style BOLD;
-    enum_constant public static final deprecated android.renderscript.Font.Style BOLD_ITALIC;
-    enum_constant public static final deprecated android.renderscript.Font.Style ITALIC;
-    enum_constant public static final deprecated android.renderscript.Font.Style NORMAL;
-  }
-
   public class Int2 {
     ctor public Int2();
     ctor public Int2(int, int);
@@ -19788,245 +20109,6 @@
     method public void transpose();
   }
 
-  public deprecated class Mesh extends android.renderscript.BaseObj {
-    method public deprecated android.renderscript.Allocation getIndexSetAllocation(int);
-    method public deprecated android.renderscript.Mesh.Primitive getPrimitive(int);
-    method public deprecated int getPrimitiveCount();
-    method public deprecated android.renderscript.Allocation getVertexAllocation(int);
-    method public deprecated int getVertexAllocationCount();
-  }
-
-  public static deprecated class Mesh.AllocationBuilder {
-    ctor public deprecated Mesh.AllocationBuilder(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.Mesh.AllocationBuilder addIndexSetAllocation(android.renderscript.Allocation, android.renderscript.Mesh.Primitive);
-    method public deprecated android.renderscript.Mesh.AllocationBuilder addIndexSetType(android.renderscript.Mesh.Primitive);
-    method public deprecated android.renderscript.Mesh.AllocationBuilder addVertexAllocation(android.renderscript.Allocation) throws java.lang.IllegalStateException;
-    method public deprecated android.renderscript.Mesh create();
-    method public deprecated int getCurrentIndexSetIndex();
-    method public deprecated int getCurrentVertexTypeIndex();
-  }
-
-  public static deprecated class Mesh.Builder {
-    ctor public deprecated Mesh.Builder(android.renderscript.RenderScript, int);
-    method public deprecated android.renderscript.Mesh.Builder addIndexSetType(android.renderscript.Type, android.renderscript.Mesh.Primitive);
-    method public deprecated android.renderscript.Mesh.Builder addIndexSetType(android.renderscript.Mesh.Primitive);
-    method public deprecated android.renderscript.Mesh.Builder addIndexSetType(android.renderscript.Element, int, android.renderscript.Mesh.Primitive);
-    method public deprecated android.renderscript.Mesh.Builder addVertexType(android.renderscript.Type) throws java.lang.IllegalStateException;
-    method public deprecated android.renderscript.Mesh.Builder addVertexType(android.renderscript.Element, int) throws java.lang.IllegalStateException;
-    method public deprecated android.renderscript.Mesh create();
-    method public deprecated int getCurrentIndexSetIndex();
-    method public deprecated int getCurrentVertexTypeIndex();
-  }
-
-  public static final deprecated class Mesh.Primitive extends java.lang.Enum {
-    method public static android.renderscript.Mesh.Primitive valueOf(java.lang.String);
-    method public static final android.renderscript.Mesh.Primitive[] values();
-    enum_constant public static final deprecated android.renderscript.Mesh.Primitive LINE;
-    enum_constant public static final deprecated android.renderscript.Mesh.Primitive LINE_STRIP;
-    enum_constant public static final deprecated android.renderscript.Mesh.Primitive POINT;
-    enum_constant public static final deprecated android.renderscript.Mesh.Primitive TRIANGLE;
-    enum_constant public static final deprecated android.renderscript.Mesh.Primitive TRIANGLE_FAN;
-    enum_constant public static final deprecated android.renderscript.Mesh.Primitive TRIANGLE_STRIP;
-  }
-
-  public static deprecated class Mesh.TriangleMeshBuilder {
-    ctor public deprecated Mesh.TriangleMeshBuilder(android.renderscript.RenderScript, int, int);
-    method public deprecated android.renderscript.Mesh.TriangleMeshBuilder addTriangle(int, int, int);
-    method public deprecated android.renderscript.Mesh.TriangleMeshBuilder addVertex(float, float);
-    method public deprecated android.renderscript.Mesh.TriangleMeshBuilder addVertex(float, float, float);
-    method public deprecated android.renderscript.Mesh create(boolean);
-    method public deprecated android.renderscript.Mesh.TriangleMeshBuilder setColor(float, float, float, float);
-    method public deprecated android.renderscript.Mesh.TriangleMeshBuilder setNormal(float, float, float);
-    method public deprecated android.renderscript.Mesh.TriangleMeshBuilder setTexture(float, float);
-    field public static final deprecated int COLOR = 1; // 0x1
-    field public static final deprecated int NORMAL = 2; // 0x2
-    field public static final deprecated int TEXTURE_0 = 256; // 0x100
-  }
-
-  public class Program extends android.renderscript.BaseObj {
-    method public void bindConstants(android.renderscript.Allocation, int);
-    method public void bindSampler(android.renderscript.Sampler, int) throws java.lang.IllegalArgumentException;
-    method public void bindTexture(android.renderscript.Allocation, int) throws java.lang.IllegalArgumentException;
-    method public android.renderscript.Type getConstant(int);
-    method public int getConstantCount();
-    method public int getTextureCount();
-    method public java.lang.String getTextureName(int);
-    method public android.renderscript.Program.TextureType getTextureType(int);
-  }
-
-  public static class Program.BaseProgramBuilder {
-    ctor protected Program.BaseProgramBuilder(android.renderscript.RenderScript);
-    method public android.renderscript.Program.BaseProgramBuilder addConstant(android.renderscript.Type) throws java.lang.IllegalStateException;
-    method public android.renderscript.Program.BaseProgramBuilder addTexture(android.renderscript.Program.TextureType) throws java.lang.IllegalArgumentException;
-    method public android.renderscript.Program.BaseProgramBuilder addTexture(android.renderscript.Program.TextureType, java.lang.String) throws java.lang.IllegalArgumentException;
-    method public int getCurrentConstantIndex();
-    method public int getCurrentTextureIndex();
-    method protected void initProgram(android.renderscript.Program);
-    method public android.renderscript.Program.BaseProgramBuilder setShader(java.lang.String);
-    method public android.renderscript.Program.BaseProgramBuilder setShader(android.content.res.Resources, int);
-  }
-
-  public static final class Program.TextureType extends java.lang.Enum {
-    method public static android.renderscript.Program.TextureType valueOf(java.lang.String);
-    method public static final android.renderscript.Program.TextureType[] values();
-    enum_constant public static final android.renderscript.Program.TextureType TEXTURE_2D;
-    enum_constant public static final android.renderscript.Program.TextureType TEXTURE_CUBE;
-  }
-
-  public deprecated class ProgramFragment extends android.renderscript.Program {
-  }
-
-  public static deprecated class ProgramFragment.Builder extends android.renderscript.Program.BaseProgramBuilder {
-    ctor public deprecated ProgramFragment.Builder(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.ProgramFragment create();
-  }
-
-  public deprecated class ProgramFragmentFixedFunction extends android.renderscript.ProgramFragment {
-  }
-
-  public static deprecated class ProgramFragmentFixedFunction.Builder {
-    ctor public deprecated ProgramFragmentFixedFunction.Builder(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.ProgramFragmentFixedFunction create();
-    method public deprecated android.renderscript.ProgramFragmentFixedFunction.Builder setPointSpriteTexCoordinateReplacement(boolean);
-    method public deprecated android.renderscript.ProgramFragmentFixedFunction.Builder setTexture(android.renderscript.ProgramFragmentFixedFunction.Builder.EnvMode, android.renderscript.ProgramFragmentFixedFunction.Builder.Format, int) throws java.lang.IllegalArgumentException;
-    method public deprecated android.renderscript.ProgramFragmentFixedFunction.Builder setVaryingColor(boolean);
-    field public static final deprecated int MAX_TEXTURE = 2; // 0x2
-  }
-
-  public static final deprecated class ProgramFragmentFixedFunction.Builder.EnvMode extends java.lang.Enum {
-    method public static android.renderscript.ProgramFragmentFixedFunction.Builder.EnvMode valueOf(java.lang.String);
-    method public static final android.renderscript.ProgramFragmentFixedFunction.Builder.EnvMode[] values();
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.EnvMode DECAL;
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.EnvMode MODULATE;
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.EnvMode REPLACE;
-  }
-
-  public static final deprecated class ProgramFragmentFixedFunction.Builder.Format extends java.lang.Enum {
-    method public static android.renderscript.ProgramFragmentFixedFunction.Builder.Format valueOf(java.lang.String);
-    method public static final android.renderscript.ProgramFragmentFixedFunction.Builder.Format[] values();
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.Format ALPHA;
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.Format LUMINANCE_ALPHA;
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.Format RGB;
-    enum_constant public static final deprecated android.renderscript.ProgramFragmentFixedFunction.Builder.Format RGBA;
-  }
-
-  public deprecated class ProgramRaster extends android.renderscript.BaseObj {
-    method public static deprecated android.renderscript.ProgramRaster CULL_BACK(android.renderscript.RenderScript);
-    method public static deprecated android.renderscript.ProgramRaster CULL_FRONT(android.renderscript.RenderScript);
-    method public static deprecated android.renderscript.ProgramRaster CULL_NONE(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.ProgramRaster.CullMode getCullMode();
-    method public deprecated boolean isPointSpriteEnabled();
-  }
-
-  public static deprecated class ProgramRaster.Builder {
-    ctor public deprecated ProgramRaster.Builder(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.ProgramRaster create();
-    method public deprecated android.renderscript.ProgramRaster.Builder setCullMode(android.renderscript.ProgramRaster.CullMode);
-    method public deprecated android.renderscript.ProgramRaster.Builder setPointSpriteEnabled(boolean);
-  }
-
-  public static final deprecated class ProgramRaster.CullMode extends java.lang.Enum {
-    method public static android.renderscript.ProgramRaster.CullMode valueOf(java.lang.String);
-    method public static final android.renderscript.ProgramRaster.CullMode[] values();
-    enum_constant public static final deprecated android.renderscript.ProgramRaster.CullMode BACK;
-    enum_constant public static final deprecated android.renderscript.ProgramRaster.CullMode FRONT;
-    enum_constant public static final deprecated android.renderscript.ProgramRaster.CullMode NONE;
-  }
-
-  public class ProgramStore extends android.renderscript.BaseObj {
-    method public static android.renderscript.ProgramStore BLEND_ALPHA_DEPTH_NONE(android.renderscript.RenderScript);
-    method public static android.renderscript.ProgramStore BLEND_ALPHA_DEPTH_TEST(android.renderscript.RenderScript);
-    method public static android.renderscript.ProgramStore BLEND_NONE_DEPTH_NONE(android.renderscript.RenderScript);
-    method public static android.renderscript.ProgramStore BLEND_NONE_DEPTH_TEST(android.renderscript.RenderScript);
-    method public android.renderscript.ProgramStore.BlendDstFunc getBlendDstFunc();
-    method public android.renderscript.ProgramStore.BlendSrcFunc getBlendSrcFunc();
-    method public android.renderscript.ProgramStore.DepthFunc getDepthFunc();
-    method public boolean isColorMaskAlphaEnabled();
-    method public boolean isColorMaskBlueEnabled();
-    method public boolean isColorMaskGreenEnabled();
-    method public boolean isColorMaskRedEnabled();
-    method public boolean isDepthMaskEnabled();
-    method public boolean isDitherEnabled();
-  }
-
-  public static final class ProgramStore.BlendDstFunc extends java.lang.Enum {
-    method public static android.renderscript.ProgramStore.BlendDstFunc valueOf(java.lang.String);
-    method public static final android.renderscript.ProgramStore.BlendDstFunc[] values();
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc DST_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc ONE;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc ONE_MINUS_DST_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc ONE_MINUS_SRC_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc ONE_MINUS_SRC_COLOR;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc SRC_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc SRC_COLOR;
-    enum_constant public static final android.renderscript.ProgramStore.BlendDstFunc ZERO;
-  }
-
-  public static final class ProgramStore.BlendSrcFunc extends java.lang.Enum {
-    method public static android.renderscript.ProgramStore.BlendSrcFunc valueOf(java.lang.String);
-    method public static final android.renderscript.ProgramStore.BlendSrcFunc[] values();
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc DST_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc DST_COLOR;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc ONE;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc ONE_MINUS_DST_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc ONE_MINUS_DST_COLOR;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc ONE_MINUS_SRC_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc SRC_ALPHA;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc SRC_ALPHA_SATURATE;
-    enum_constant public static final android.renderscript.ProgramStore.BlendSrcFunc ZERO;
-  }
-
-  public static class ProgramStore.Builder {
-    ctor public ProgramStore.Builder(android.renderscript.RenderScript);
-    method public android.renderscript.ProgramStore create();
-    method public android.renderscript.ProgramStore.Builder setBlendFunc(android.renderscript.ProgramStore.BlendSrcFunc, android.renderscript.ProgramStore.BlendDstFunc);
-    method public android.renderscript.ProgramStore.Builder setColorMaskEnabled(boolean, boolean, boolean, boolean);
-    method public android.renderscript.ProgramStore.Builder setDepthFunc(android.renderscript.ProgramStore.DepthFunc);
-    method public android.renderscript.ProgramStore.Builder setDepthMaskEnabled(boolean);
-    method public android.renderscript.ProgramStore.Builder setDitherEnabled(boolean);
-  }
-
-  public static final class ProgramStore.DepthFunc extends java.lang.Enum {
-    method public static android.renderscript.ProgramStore.DepthFunc valueOf(java.lang.String);
-    method public static final android.renderscript.ProgramStore.DepthFunc[] values();
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc ALWAYS;
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc EQUAL;
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc GREATER;
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc GREATER_OR_EQUAL;
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc LESS;
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc LESS_OR_EQUAL;
-    enum_constant public static final android.renderscript.ProgramStore.DepthFunc NOT_EQUAL;
-  }
-
-  public deprecated class ProgramVertex extends android.renderscript.Program {
-    method public deprecated android.renderscript.Element getInput(int);
-    method public deprecated int getInputCount();
-  }
-
-  public static deprecated class ProgramVertex.Builder extends android.renderscript.Program.BaseProgramBuilder {
-    ctor public deprecated ProgramVertex.Builder(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.ProgramVertex.Builder addInput(android.renderscript.Element) throws java.lang.IllegalStateException;
-    method public deprecated android.renderscript.ProgramVertex create();
-  }
-
-  public deprecated class ProgramVertexFixedFunction extends android.renderscript.ProgramVertex {
-    method public deprecated void bindConstants(android.renderscript.ProgramVertexFixedFunction.Constants);
-  }
-
-  public static deprecated class ProgramVertexFixedFunction.Builder {
-    ctor public deprecated ProgramVertexFixedFunction.Builder(android.renderscript.RenderScript);
-    method public deprecated android.renderscript.ProgramVertexFixedFunction create();
-    method public deprecated android.renderscript.ProgramVertexFixedFunction.Builder setTextureMatrixEnable(boolean);
-  }
-
-  public static deprecated class ProgramVertexFixedFunction.Constants {
-    ctor public deprecated ProgramVertexFixedFunction.Constants(android.renderscript.RenderScript);
-    method public deprecated void destroy();
-    method public deprecated void setModelview(android.renderscript.Matrix4f);
-    method public deprecated void setProjection(android.renderscript.Matrix4f);
-    method public deprecated void setTexture(android.renderscript.Matrix4f);
-  }
-
   public class RSDriverException extends android.renderscript.RSRuntimeException {
     ctor public RSDriverException(java.lang.String);
   }
@@ -20043,35 +20125,6 @@
     ctor public RSRuntimeException(java.lang.String);
   }
 
-  public deprecated class RSSurfaceView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback {
-    ctor public deprecated RSSurfaceView(android.content.Context);
-    ctor public deprecated RSSurfaceView(android.content.Context, android.util.AttributeSet);
-    method public deprecated android.renderscript.RenderScriptGL createRenderScriptGL(android.renderscript.RenderScriptGL.SurfaceConfig);
-    method public deprecated void destroyRenderScriptGL();
-    method public deprecated android.renderscript.RenderScriptGL getRenderScriptGL();
-    method public deprecated void pause();
-    method public deprecated void resume();
-    method public deprecated void setRenderScriptGL(android.renderscript.RenderScriptGL);
-    method public deprecated void surfaceChanged(android.view.SurfaceHolder, int, int, int);
-    method public deprecated void surfaceCreated(android.view.SurfaceHolder);
-    method public deprecated void surfaceDestroyed(android.view.SurfaceHolder);
-  }
-
-  public deprecated class RSTextureView extends android.view.TextureView implements android.view.TextureView.SurfaceTextureListener {
-    ctor public deprecated RSTextureView(android.content.Context);
-    ctor public deprecated RSTextureView(android.content.Context, android.util.AttributeSet);
-    method public deprecated android.renderscript.RenderScriptGL createRenderScriptGL(android.renderscript.RenderScriptGL.SurfaceConfig);
-    method public deprecated void destroyRenderScriptGL();
-    method public deprecated android.renderscript.RenderScriptGL getRenderScriptGL();
-    method public deprecated void onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int);
-    method public deprecated boolean onSurfaceTextureDestroyed(android.graphics.SurfaceTexture);
-    method public deprecated void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
-    method public deprecated void onSurfaceTextureUpdated(android.graphics.SurfaceTexture);
-    method public deprecated void pause();
-    method public deprecated void resume();
-    method public deprecated void setRenderScriptGL(android.renderscript.RenderScriptGL);
-  }
-
   public class RenderScript {
     method public void contextDump();
     method public static android.renderscript.RenderScript create(android.content.Context);
@@ -20115,30 +20168,6 @@
     field protected int mLength;
   }
 
-  public deprecated class RenderScriptGL extends android.renderscript.RenderScript {
-    ctor public deprecated RenderScriptGL(android.content.Context, android.renderscript.RenderScriptGL.SurfaceConfig);
-    method public deprecated void bindProgramFragment(android.renderscript.ProgramFragment);
-    method public deprecated void bindProgramRaster(android.renderscript.ProgramRaster);
-    method public deprecated void bindProgramStore(android.renderscript.ProgramStore);
-    method public deprecated void bindProgramVertex(android.renderscript.ProgramVertex);
-    method public deprecated void bindRootScript(android.renderscript.Script);
-    method public deprecated int getHeight();
-    method public deprecated int getWidth();
-    method public deprecated void pause();
-    method public deprecated void resume();
-    method public deprecated void setSurface(android.view.SurfaceHolder, int, int);
-    method public deprecated void setSurfaceTexture(android.graphics.SurfaceTexture, int, int);
-  }
-
-  public static deprecated class RenderScriptGL.SurfaceConfig {
-    ctor public deprecated RenderScriptGL.SurfaceConfig();
-    ctor public deprecated RenderScriptGL.SurfaceConfig(android.renderscript.RenderScriptGL.SurfaceConfig);
-    method public deprecated void setAlpha(int, int);
-    method public deprecated void setColor(int, int);
-    method public deprecated void setDepth(int, int);
-    method public deprecated void setSamples(int, int, float);
-  }
-
   public class Sampler extends android.renderscript.BaseObj {
     method public static android.renderscript.Sampler CLAMP_LINEAR(android.renderscript.RenderScript);
     method public static android.renderscript.Sampler CLAMP_LINEAR_MIP_LINEAR(android.renderscript.RenderScript);
@@ -20452,12 +20481,27 @@
 
 package android.security {
 
+  public class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+  }
+
+  public static class AndroidKeyPairGeneratorSpec.Builder {
+    ctor public AndroidKeyPairGeneratorSpec.Builder(android.content.Context);
+    method public android.security.AndroidKeyPairGeneratorSpec build();
+    method public android.security.AndroidKeyPairGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.AndroidKeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.AndroidKeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
+    method public android.security.AndroidKeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
+    method public android.security.AndroidKeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+  }
+
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
     method public static android.content.Intent createInstallIntent();
     method public static java.security.cert.X509Certificate[] getCertificateChain(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
     method public static java.security.PrivateKey getPrivateKey(android.content.Context, java.lang.String) throws java.lang.InterruptedException, android.security.KeyChainException;
+    method public static boolean isBoundKeyAlgorithm(java.lang.String);
+    method public static boolean isKeyAlgorithmSupported(java.lang.String);
     field public static final java.lang.String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
     field public static final java.lang.String EXTRA_CERTIFICATE = "CERT";
     field public static final java.lang.String EXTRA_NAME = "name";
@@ -20525,6 +20569,38 @@
 
 }
 
+package android.service.notification {
+
+  public abstract class NotificationListenerService extends android.app.Service {
+    ctor public NotificationListenerService();
+    method public final void clearAllNotifications();
+    method public final void clearNotification(java.lang.String, java.lang.String, int);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
+    method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
+  }
+
+  public class StatusBarNotification implements android.os.Parcelable {
+    ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
+    ctor public StatusBarNotification(android.os.Parcel);
+    method public android.service.notification.StatusBarNotification clone();
+    method public int describeContents();
+    method public int getUserId();
+    method public boolean isClearable();
+    method public boolean isOngoing();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public final int id;
+    field public final android.app.Notification notification;
+    field public final java.lang.String pkg;
+    field public final long postTime;
+    field public final java.lang.String tag;
+    field public final android.os.UserHandle user;
+  }
+
+}
+
 package android.service.textservice {
 
   public abstract class SpellCheckerService extends android.app.Service {
@@ -21148,6 +21224,7 @@
     method public int getDataState();
     method public java.lang.String getDeviceId();
     method public java.lang.String getDeviceSoftwareVersion();
+    method public java.lang.String getGroupIdLevel1();
     method public java.lang.String getLine1Number();
     method public java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
     method public java.lang.String getNetworkCountryIso();
@@ -22505,25 +22582,26 @@
     method public static java.lang.CharSequence format(java.lang.CharSequence, long);
     method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Date);
     method public static java.lang.CharSequence format(java.lang.CharSequence, java.util.Calendar);
+    method public static java.lang.String getBestDateTimePattern(java.util.Locale, java.lang.String);
     method public static java.text.DateFormat getDateFormat(android.content.Context);
     method public static char[] getDateFormatOrder(android.content.Context);
     method public static java.text.DateFormat getLongDateFormat(android.content.Context);
     method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
     method public static java.text.DateFormat getTimeFormat(android.content.Context);
     method public static boolean is24HourFormat(android.content.Context);
-    field public static final char AM_PM = 97; // 0x0061 'a'
-    field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A'
-    field public static final char DATE = 100; // 0x0064 'd'
-    field public static final char DAY = 69; // 0x0045 'E'
-    field public static final char HOUR = 104; // 0x0068 'h'
-    field public static final char HOUR_OF_DAY = 107; // 0x006b 'k'
-    field public static final char MINUTE = 109; // 0x006d 'm'
-    field public static final char MONTH = 77; // 0x004d 'M'
-    field public static final char QUOTE = 39; // 0x0027 '\''
-    field public static final char SECONDS = 115; // 0x0073 's'
-    field public static final char STANDALONE_MONTH = 76; // 0x004c 'L'
-    field public static final char TIME_ZONE = 122; // 0x007a 'z'
-    field public static final char YEAR = 121; // 0x0079 'y'
+    field public static final deprecated char AM_PM = 97; // 0x0061 'a'
+    field public static final deprecated char CAPITAL_AM_PM = 65; // 0x0041 'A'
+    field public static final deprecated char DATE = 100; // 0x0064 'd'
+    field public static final deprecated char DAY = 69; // 0x0045 'E'
+    field public static final deprecated char HOUR = 104; // 0x0068 'h'
+    field public static final deprecated char HOUR_OF_DAY = 107; // 0x006b 'k'
+    field public static final deprecated char MINUTE = 109; // 0x006d 'm'
+    field public static final deprecated char MONTH = 77; // 0x004d 'M'
+    field public static final deprecated char QUOTE = 39; // 0x0027 '\''
+    field public static final deprecated char SECONDS = 115; // 0x0073 's'
+    field public static final deprecated char STANDALONE_MONTH = 76; // 0x004c 'L'
+    field public static final deprecated char TIME_ZONE = 122; // 0x007a 'z'
+    field public static final deprecated char YEAR = 121; // 0x0079 'y'
   }
 
   public class DateUtils {
@@ -24150,6 +24228,7 @@
     field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
     field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
     field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
     field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
     field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
     field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
@@ -24161,6 +24240,7 @@
     field public static final int SOURCE_STYLUS = 16386; // 0x4002
     field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
     field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
     field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
     field public static final int SOURCE_UNKNOWN = 0; // 0x0
   }
@@ -24172,7 +24252,9 @@
     method public float getMax();
     method public float getMin();
     method public float getRange();
+    method public float getResolution();
     method public int getSource();
+    method public boolean isFromSource(int);
   }
 
   public abstract class InputEvent implements android.os.Parcelable {
@@ -24181,6 +24263,7 @@
     method public abstract int getDeviceId();
     method public abstract long getEventTime();
     method public abstract int getSource();
+    method public boolean isFromSource(int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
@@ -25231,6 +25314,7 @@
     method public int getNextFocusUpId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public int getOverScrollMode();
+    method public android.view.ViewOverlay getOverlay();
     method public int getPaddingBottom();
     method public int getPaddingEnd();
     method public int getPaddingLeft();
@@ -25971,12 +26055,23 @@
     method public abstract void onChildViewRemoved(android.view.View, android.view.View);
   }
 
+  public class ViewGroupOverlay extends android.view.ViewOverlay {
+    method public void add(android.view.View);
+    method public void remove(android.view.View);
+  }
+
   public abstract interface ViewManager {
     method public abstract void addView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public abstract void removeView(android.view.View);
     method public abstract void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
   }
 
+  public class ViewOverlay {
+    method public void add(android.graphics.drawable.Drawable);
+    method public void clear();
+    method public void remove(android.graphics.drawable.Drawable);
+  }
+
   public abstract interface ViewParent {
     method public abstract void bringChildToFront(android.view.View);
     method public abstract void childDrawableStateChanged(android.view.View);
@@ -26062,6 +26157,8 @@
     method public void addOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
     method public void addOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
     method public void addOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
+    method public void addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
+    method public void addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
     method public final void dispatchOnDraw();
     method public final void dispatchOnGlobalLayout();
     method public final boolean dispatchOnPreDraw();
@@ -26073,6 +26170,8 @@
     method public void removeOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
     method public void removeOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
     method public void removeOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
+    method public void removeOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener);
+    method public void removeOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener);
   }
 
   public static abstract interface ViewTreeObserver.OnDrawListener {
@@ -26099,6 +26198,15 @@
     method public abstract void onTouchModeChanged(boolean);
   }
 
+  public static abstract interface ViewTreeObserver.OnWindowAttachListener {
+    method public abstract void onWindowAttached();
+    method public abstract void onWindowDetached();
+  }
+
+  public static abstract interface ViewTreeObserver.OnWindowFocusChangeListener {
+    method public abstract void onWindowFocusChanged(boolean);
+  }
+
   public abstract class Window {
     ctor public Window(android.content.Context);
     method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
@@ -27529,8 +27637,6 @@
     method public synchronized int getMinimumFontSize();
     method public synchronized int getMinimumLogicalFontSize();
     method public deprecated synchronized android.webkit.WebSettings.PluginState getPluginState();
-    method public deprecated synchronized boolean getPluginsEnabled();
-    method public deprecated synchronized java.lang.String getPluginsPath();
     method public synchronized java.lang.String getSansSerifFontFamily();
     method public boolean getSaveFormData();
     method public deprecated boolean getSavePassword();
@@ -27576,8 +27682,6 @@
     method public synchronized void setMinimumLogicalFontSize(int);
     method public void setNeedInitialFocus(boolean);
     method public deprecated synchronized void setPluginState(android.webkit.WebSettings.PluginState);
-    method public deprecated synchronized void setPluginsEnabled(boolean);
-    method public deprecated synchronized void setPluginsPath(java.lang.String);
     method public deprecated synchronized void setRenderPriority(android.webkit.WebSettings.RenderPriority);
     method public synchronized void setSansSerifFontFamily(java.lang.String);
     method public void setSaveFormData(boolean);
@@ -28528,8 +28632,10 @@
     method public void setChildDivider(android.graphics.drawable.Drawable);
     method public void setChildIndicator(android.graphics.drawable.Drawable);
     method public void setChildIndicatorBounds(int, int);
+    method public void setChildIndicatorBoundsRelative(int, int);
     method public void setGroupIndicator(android.graphics.drawable.Drawable);
     method public void setIndicatorBounds(int, int);
+    method public void setIndicatorBoundsRelative(int, int);
     method public void setOnChildClickListener(android.widget.ExpandableListView.OnChildClickListener);
     method public void setOnGroupClickListener(android.widget.ExpandableListView.OnGroupClickListener);
     method public void setOnGroupCollapseListener(android.widget.ExpandableListView.OnGroupCollapseListener);
@@ -29828,8 +29934,8 @@
     method public void setFormat12Hour(java.lang.CharSequence);
     method public void setFormat24Hour(java.lang.CharSequence);
     method public void setTimeZone(java.lang.String);
-    field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
-    field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
+    field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_12_HOUR;
+    field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_24_HOUR;
   }
 
   public class TextSwitcher extends android.widget.ViewSwitcher {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 9fa7dbb..ccb9e1f 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -39,6 +39,7 @@
 import android.os.UserHandle;
 import android.util.AndroidException;
 import android.view.IWindowManager;
+import com.android.internal.os.BaseCommand;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -50,12 +51,9 @@
 import java.util.HashSet;
 import java.util.List;
 
-public class Am {
+public class Am extends BaseCommand {
 
     private IActivityManager mAm;
-    private String[] mArgs;
-    private int mNextArg;
-    private String mCurArgData;
 
     private int mStartFlags = 0;
     private boolean mWaitOption = false;
@@ -63,36 +61,159 @@
 
     private int mRepeat = 0;
     private int mUserId;
+    private String mReceiverPermission;
 
     private String mProfileFile;
 
-    // These are magic strings understood by the Eclipse plugin.
-    private static final String FATAL_ERROR_CODE = "Error type 1";
-    private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
-    private static final String NO_CLASS_ERROR_CODE = "Error type 3";
-
     /**
      * Command-line entry point.
      *
      * @param args The command-line arguments
      */
     public static void main(String[] args) {
-        try {
-            (new Am()).run(args);
-        } catch (IllegalArgumentException e) {
-            showUsage();
-            System.err.println("Error: " + e.getMessage());
-        } catch (Exception e) {
-            e.printStackTrace(System.err);
-            System.exit(1);
-        }
+        (new Am()).run(args);
     }
 
-    private void run(String[] args) throws Exception {
-        if (args.length < 1) {
-            showUsage();
-            return;
-        }
+    public void onShowUsage(PrintStream out) {
+        out.println(
+                "usage: am [subcommand] [options]\n" +
+                "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
+                "               [--R COUNT] [-S] [--opengl-trace]\n" +
+                "               [--user <USER_ID> | current] <INTENT>\n" +
+                "       am startservice [--user <USER_ID> | current] <INTENT>\n" +
+                "       am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" +
+                "       am kill [--user <USER_ID> | all | current] <PACKAGE>\n" +
+                "       am kill-all\n" +
+                "       am broadcast [--user <USER_ID> | all | current] <INTENT>\n" +
+                "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
+                "               [--user <USER_ID> | current]\n" +
+                "               [--no-window-animation] <COMPONENT>\n" +
+                "       am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
+                "       am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
+                "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
+                "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
+                "       am clear-debug-app\n" +
+                "       am monitor [--gdb <port>]\n" +
+                "       am screen-compat [on|off] <PACKAGE>\n" +
+                "       am to-uri [INTENT]\n" +
+                "       am to-intent-uri [INTENT]\n" +
+                "       am switch-user <USER_ID>\n" +
+                "       am stop-user <USER_ID>\n" +
+                "\n" +
+                "am start: start an Activity.  Options are:\n" +
+                "    -D: enable debugging\n" +
+                "    -W: wait for launch to complete\n" +
+                "    --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
+                "    -P <FILE>: like above, but profiling stops when app goes idle\n" +
+                "    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,\n" +
+                "        the top activity will be finished.\n" +
+                "    -S: force stop the target app before starting the activity\n" +
+                "    --opengl-trace: enable tracing of OpenGL functions\n" +
+                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
+                "        specified then run as the current user.\n" +
+                "\n" +
+                "am startservice: start a Service.  Options are:\n" +
+                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
+                "        specified then run as the current user.\n" +
+                "\n" +
+                "am force-stop: force stop everything associated with <PACKAGE>.\n" +
+                "    --user <USER_ID> | all | current: Specify user to force stop;\n" +
+                "        all users if not specified.\n" +
+                "\n" +
+                "am kill: Kill all processes associated with <PACKAGE>.  Only kills.\n" +
+                "  processes that are safe to kill -- that is, will not impact the user\n" +
+                "  experience.\n" +
+                "    --user <USER_ID> | all | current: Specify user whose processes to kill;\n" +
+                "        all users if not specified.\n" +
+                "\n" +
+                "am kill-all: Kill all background processes.\n" +
+                "\n" +
+                "am broadcast: send a broadcast Intent.  Options are:\n" +
+                "    --user <USER_ID> | all | current: Specify which user to send to; if not\n" +
+                "        specified then send to all users.\n" +
+                "    --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" +
+                "\n" +
+                "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
+                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
+                "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
+                "        [-e perf true] to generate raw output for performance measurements.\n" +
+                "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
+                "        common form is [-e <testrunner_flag> <value>[,<value>...]].\n" +
+                "    -p <FILE>: write profiling data to <FILE>\n" +
+                "    -w: wait for instrumentation to finish before returning.  Required for\n" +
+                "        test runners.\n" +
+                "    --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
+                "        current user if not specified.\n" +
+                "    --no-window-animation: turn off window animations will running.\n" +
+                "\n" +
+                "am profile: start and stop profiler on a process.  The given <PROCESS> argument\n" +
+                "  may be either a process name or pid.  Options are:\n" +
+                "    --user <USER_ID> | current: When supplying a process name,\n" +
+                "        specify user of process to profile; uses current user if not specified.\n" +
+                "\n" +
+                "am dumpheap: dump the heap of a process.  The given <PROCESS> argument may\n" +
+                "  be either a process name or pid.  Options are:\n" +
+                "    -n: dump native heap instead of managed heap\n" +
+                "    --user <USER_ID> | current: When supplying a process name,\n" +
+                "        specify user of process to dump; uses current user if not specified.\n" +
+                "\n" +
+                "am set-debug-app: set application <PACKAGE> to debug.  Options are:\n" +
+                "    -w: wait for debugger when application starts\n" +
+                "    --persistent: retain this value\n" +
+                "\n" +
+                "am clear-debug-app: clear the previously set-debug-app.\n" +
+                "\n" +
+                "am bug-report: request bug report generation; will launch UI\n" +
+                "    when done to select where it should be delivered.\n" +
+                "\n" +
+                "am monitor: start monitoring for crashes or ANRs.\n" +
+                "    --gdb: start gdbserv on the given port at crash/ANR\n" +
+                "\n" +
+                "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
+                "\n" +
+                "am to-uri: print the given Intent specification as a URI.\n" +
+                "\n" +
+                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
+                "\n" +
+                "am switch-user: switch to put USER_ID in the foreground, starting\n" +
+                "  execution of that user if it is currently stopped.\n" +
+                "\n" +
+                "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
+                "  code until a later explicit switch to it.\n" +
+                "\n" +
+                "<INTENT> specifications include these flags and arguments:\n" +
+                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
+                "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
+                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
+                "    [--esn <EXTRA_KEY> ...]\n" +
+                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
+                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
+                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
+                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
+                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
+                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
+                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
+                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
+                "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
+                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
+                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
+                "    [--include-stopped-packages]\n" +
+                "    [--activity-brought-to-front] [--activity-clear-top]\n" +
+                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
+                "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
+                "    [--activity-no-animation] [--activity-no-history]\n" +
+                "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
+                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
+                "    [--activity-single-top] [--activity-clear-task]\n" +
+                "    [--activity-task-on-home]\n" +
+                "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
+                "    [--selector]\n" +
+                "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
+                );
+    }
+
+    public void onRun() throws Exception {
 
         mAm = ActivityManagerNative.getDefault();
         if (mAm == null) {
@@ -100,9 +221,7 @@
             throw new AndroidException("Can't connect to activity manager; is the system running?");
         }
 
-        mArgs = args;
-        String op = args[0];
-        mNextArg = 1;
+        String op = nextArgRequired();
 
         if (op.equals("start")) {
             runStart();
@@ -141,7 +260,7 @@
         } else if (op.equals("stop-user")) {
             runStopUser();
         } else {
-            throw new IllegalArgumentException("Unknown command: " + op);
+            showError("Error: unknown command '" + op + "'");
         }
     }
 
@@ -332,6 +451,8 @@
                 mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES;
             } else if (opt.equals("--user")) {
                 mUserId = parseUserArg(nextArgRequired());
+            } else if (opt.equals("--receiver-permission")) {
+                mReceiverPermission = nextArgRequired();
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return null;
@@ -608,7 +729,7 @@
         Intent intent = makeIntent(UserHandle.USER_ALL);
         IntentReceiver receiver = new IntentReceiver();
         System.out.println("Broadcasting: " + intent);
-        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null,
+        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission,
                 android.app.AppOpsManager.OP_NONE, true, false, mUserId);
         receiver.waitForFinish();
     }
@@ -1300,192 +1421,4 @@
             return true;
         }
     }
-
-    private String nextOption() {
-        if (mCurArgData != null) {
-            String prev = mArgs[mNextArg - 1];
-            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
-        }
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mNextArg];
-        if (!arg.startsWith("-")) {
-            return null;
-        }
-        mNextArg++;
-        if (arg.equals("--")) {
-            return null;
-        }
-        if (arg.length() > 1 && arg.charAt(1) != '-') {
-            if (arg.length() > 2) {
-                mCurArgData = arg.substring(2);
-                return arg.substring(0, 2);
-            } else {
-                mCurArgData = null;
-                return arg;
-            }
-        }
-        mCurArgData = null;
-        return arg;
-    }
-
-    private String nextArg() {
-        if (mCurArgData != null) {
-            String arg = mCurArgData;
-            mCurArgData = null;
-            return arg;
-        } else if (mNextArg < mArgs.length) {
-            return mArgs[mNextArg++];
-        } else {
-            return null;
-        }
-    }
-
-    private String nextArgRequired() {
-        String arg = nextArg();
-        if (arg == null) {
-            String prev = mArgs[mNextArg - 1];
-            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
-        }
-        return arg;
-    }
-
-    private static void showUsage() {
-        System.err.println(
-                "usage: am [subcommand] [options]\n" +
-                "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
-                "               [--R COUNT] [-S] [--opengl-trace]\n" +
-                "               [--user <USER_ID> | current] <INTENT>\n" +
-                "       am startservice [--user <USER_ID> | current] <INTENT>\n" +
-                "       am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" +
-                "       am kill [--user <USER_ID> | all | current] <PACKAGE>\n" +
-                "       am kill-all\n" +
-                "       am broadcast [--user <USER_ID> | all | current] <INTENT>\n" +
-                "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
-                "               [--user <USER_ID> | current]\n" +
-                "               [--no-window-animation] <COMPONENT>\n" +
-                "       am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
-                "       am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
-                "       am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
-                "       am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
-                "       am clear-debug-app\n" +
-                "       am monitor [--gdb <port>]\n" +
-                "       am screen-compat [on|off] <PACKAGE>\n" +
-                "       am to-uri [INTENT]\n" +
-                "       am to-intent-uri [INTENT]\n" +
-                "       am switch-user <USER_ID>\n" +
-                "       am stop-user <USER_ID>\n" +
-                "\n" +
-                "am start: start an Activity.  Options are:\n" +
-                "    -D: enable debugging\n" +
-                "    -W: wait for launch to complete\n" +
-                "    --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
-                "    -P <FILE>: like above, but profiling stops when app goes idle\n" +
-                "    -R: repeat the activity launch <COUNT> times.  Prior to each repeat,\n" +
-                "        the top activity will be finished.\n" +
-                "    -S: force stop the target app before starting the activity\n" +
-                "    --opengl-trace: enable tracing of OpenGL functions\n" +
-                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
-                "        specified then run as the current user.\n" +
-                "\n" +
-                "am startservice: start a Service.  Options are:\n" +
-                "    --user <USER_ID> | current: Specify which user to run as; if not\n" +
-                "        specified then run as the current user.\n" +
-                "\n" +
-                "am force-stop: force stop everything associated with <PACKAGE>.\n" +
-                "    --user <USER_ID> | all | current: Specify user to force stop;\n" +
-                "        all users if not specified.\n" +
-                "\n" +
-                "am kill: Kill all processes associated with <PACKAGE>.  Only kills.\n" +
-                "  processes that are safe to kill -- that is, will not impact the user\n" +
-                "  experience.\n" +
-                "    --user <USER_ID> | all | current: Specify user whose processes to kill;\n" +
-                "        all users if not specified.\n" +
-                "\n" +
-                "am kill-all: Kill all background processes.\n" +
-                "\n" +
-                "am broadcast: send a broadcast Intent.  Options are:\n" +
-                "    --user <USER_ID> | all | current: Specify which user to send to; if not\n" +
-                "        specified then send to all users.\n" +
-                "\n" +
-                "am instrument: start an Instrumentation.  Typically this target <COMPONENT>\n" +
-                "  is the form <TEST_PACKAGE>/<RUNNER_CLASS>.  Options are:\n" +
-                "    -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT).  Use with\n" +
-                "        [-e perf true] to generate raw output for performance measurements.\n" +
-                "    -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a\n" +
-                "        common form is [-e <testrunner_flag> <value>[,<value>...]].\n" +
-                "    -p <FILE>: write profiling data to <FILE>\n" +
-                "    -w: wait for instrumentation to finish before returning.  Required for\n" +
-                "        test runners.\n" +
-                "    --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
-                "        current user if not specified.\n" +
-                "    --no-window-animation: turn off window animations will running.\n" +
-                "\n" +
-                "am profile: start and stop profiler on a process.  The given <PROCESS> argument\n" +
-                "  may be either a process name or pid.  Options are:\n" +
-                "    --user <USER_ID> | current: When supplying a process name,\n" +
-                "        specify user of process to profile; uses current user if not specified.\n" +
-                "\n" +
-                "am dumpheap: dump the heap of a process.  The given <PROCESS> argument may\n" +
-                "  be either a process name or pid.  Options are:\n" +
-                "    -n: dump native heap instead of managed heap\n" +
-                "    --user <USER_ID> | current: When supplying a process name,\n" +
-                "        specify user of process to dump; uses current user if not specified.\n" +
-                "\n" +
-                "am set-debug-app: set application <PACKAGE> to debug.  Options are:\n" +
-                "    -w: wait for debugger when application starts\n" +
-                "    --persistent: retain this value\n" +
-                "\n" +
-                "am clear-debug-app: clear the previously set-debug-app.\n" +
-                "\n" +
-                "am bug-report: request bug report generation; will launch UI\n" +
-                "    when done to select where it should be delivered.\n" +
-                "\n" +
-                "am monitor: start monitoring for crashes or ANRs.\n" +
-                "    --gdb: start gdbserv on the given port at crash/ANR\n" +
-                "\n" +
-                "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
-                "\n" +
-                "am to-uri: print the given Intent specification as a URI.\n" +
-                "\n" +
-                "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
-                "\n" +
-                "am switch-user: switch to put USER_ID in the foreground, starting\n" +
-                "  execution of that user if it is currently stopped.\n" +
-                "\n" +
-                "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
-                "  code until a later explicit switch to it.\n" +
-                "\n" +
-                "<INTENT> specifications include these flags and arguments:\n" +
-                "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
-                "    [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
-                "    [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
-                "    [--esn <EXTRA_KEY> ...]\n" +
-                "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
-                "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
-                "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
-                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
-                "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
-                "    [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
-                "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
-                "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
-                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
-                "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
-                "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
-                "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
-                "    [--include-stopped-packages]\n" +
-                "    [--activity-brought-to-front] [--activity-clear-top]\n" +
-                "    [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" +
-                "    [--activity-launched-from-history] [--activity-multiple-task]\n" +
-                "    [--activity-no-animation] [--activity-no-history]\n" +
-                "    [--activity-no-user-action] [--activity-previous-is-top]\n" +
-                "    [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" +
-                "    [--activity-single-top] [--activity-clear-task]\n" +
-                "    [--activity-task-on-home]\n" +
-                "    [--receiver-registered-only] [--receiver-replace-pending]\n" +
-                "    [--selector]\n" +
-                "    [<URI> | <PACKAGE> | <COMPONENT>]\n"
-                );
-    }
 }
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index b39c335..b9afe40 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
+	liblog \
 	libbinder \
 	libandroid_runtime
 
@@ -27,6 +28,7 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
+	liblog \
 	libbinder \
 	libandroid_runtime
 
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 6fe358c..0668be6 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -13,7 +13,9 @@
 #include <cutils/process_name.h>
 #include <cutils/memory.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <sys/personality.h>
 
+#include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 
@@ -128,8 +130,32 @@
     strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
 }
 
-int main(int argc, const char* const argv[])
+int main(int argc, char* const argv[])
 {
+#ifdef __arm__
+    /*
+     * b/7188322 - Temporarily revert to the compat memory layout
+     * to avoid breaking third party apps.
+     *
+     * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
+     *
+     * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
+     * changes the kernel mapping from bottom up to top-down.
+     * This breaks some programs which improperly embed
+     * an out of date copy of Android's linker.
+     */
+    if (getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) {
+        int current = personality(0xFFFFFFFF);
+        if ((current & ADDR_COMPAT_LAYOUT) == 0) {
+            personality(current | ADDR_COMPAT_LAYOUT);
+            setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
+            execv("/system/bin/app_process", argv);
+            return -1;
+        }
+    }
+    unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
+#endif
+
     // These are global variables in ProcessState.cpp
     mArgC = argc;
     mArgV = argv;
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 8c46b21..d5ff84e 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -9,6 +9,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	liblog \
 	libandroidfw \
 	libutils \
 	libbinder \
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java
index 046ccca..73fd660 100644
--- a/cmds/bu/src/com/android/commands/bu/Backup.java
+++ b/cmds/bu/src/com/android/commands/bu/Backup.java
@@ -22,6 +22,7 @@
 import android.os.ServiceManager;
 import android.util.Log;
 
+import java.io.IOException;
 import java.util.ArrayList;
 
 public final class Backup {
@@ -64,6 +65,7 @@
     private void doFullBackup(int socketFd) {
         ArrayList<String> packages = new ArrayList<String>();
         boolean saveApks = false;
+        boolean saveObbs = false;
         boolean saveShared = false;
         boolean doEverything = false;
         boolean allIncludesSystem = true;
@@ -75,6 +77,10 @@
                     saveApks = true;
                 } else if ("-noapk".equals(arg)) {
                     saveApks = false;
+                } else if ("-obb".equals(arg)) {
+                    saveObbs = true;
+                } else if ("-noobb".equals(arg)) {
+                    saveObbs = false;
                 } else if ("-shared".equals(arg)) {
                     saveShared = true;
                 } else if ("-noshared".equals(arg)) {
@@ -104,23 +110,37 @@
             return;
         }
 
+        ParcelFileDescriptor fd = null;
         try {
-            ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd);
+            fd = ParcelFileDescriptor.adoptFd(socketFd);
             String[] packArray = new String[packages.size()];
-            mBackupManager.fullBackup(fd, saveApks, saveShared, doEverything, allIncludesSystem,
-                    packages.toArray(packArray));
+            mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doEverything,
+                    allIncludesSystem, packages.toArray(packArray));
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to invoke backup manager for backup");
+        } finally {
+            if (fd != null) {
+                try {
+                    fd.close();
+                } catch (IOException e) {}
+            }
         }
     }
 
     private void doFullRestore(int socketFd) {
         // No arguments to restore
+        ParcelFileDescriptor fd = null;
         try {
-            ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd);
+            fd = ParcelFileDescriptor.adoptFd(socketFd);
             mBackupManager.fullRestore(fd);
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to invoke backup manager for restore");
+        } finally {
+            if (fd != null) {
+                try {
+                    fd.close();
+                } catch (IOException e) {}
+            }
         }
     }
 
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index cdbc405..e43501c 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -75,11 +75,14 @@
                             Float.parseFloat(args[3]), Float.parseFloat(args[4]), -1);
                     return;
                 }
-            } else if (command.equals("touchscreen") || command.equals("touchpad")) {
+            } else if (command.equals("touchscreen") || command.equals("touchpad")
+                    || command.equals("touchnavigation")) {
                 // determine input source
                 int inputSource = InputDevice.SOURCE_TOUCHSCREEN;
                 if (command.equals("touchpad")) {
                     inputSource = InputDevice.SOURCE_TOUCHPAD;
+                } else if (command.equals("touchnavigation")) {
+                    inputSource = InputDevice.SOURCE_TOUCH_NAVIGATION;
                 }
                 // determine subcommand
                 if (args.length > 1) {
@@ -247,8 +250,9 @@
         System.err.println("usage: input ...");
         System.err.println("       input text <string>");
         System.err.println("       input keyevent <key code number or name>");
-        System.err.println("       input [touchscreen|touchpad] tap <x> <y>");
-        System.err.println("       input [touchscreen|touchpad] swipe <x1> <y1> <x2> <y2> [duration(ms)]");
+        System.err.println("       input [touchscreen|touchpad|touchnavigation] tap <x> <y>");
+        System.err.println("       input [touchscreen|touchpad|touchnavigation] swipe "
+                + "<x1> <y1> <x2> <y2> [duration(ms)]");
         System.err.println("       input trackball press");
         System.err.println("       input trackball roll <dx> <dy>");
     }
diff --git a/cmds/interrupter/Android.mk b/cmds/interrupter/Android.mk
new file mode 100644
index 0000000..e324627
--- /dev/null
+++ b/cmds/interrupter/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    interrupter.c
+LOCAL_MODULE := interrupter
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_LDFLAGS := -ldl
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    interrupter.c
+LOCAL_MODULE := interrupter
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_LDFLAGS := -ldl
+
+include $(BUILD_HOST_SHARED_LIBRARY)
\ No newline at end of file
diff --git a/cmds/interrupter/interrupter.c b/cmds/interrupter/interrupter.c
new file mode 100644
index 0000000..ae55515
--- /dev/null
+++ b/cmds/interrupter/interrupter.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 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.
+ */
+
+
+/**
+ * The probability of a syscall failing from 0.0 to 1.0
+ */
+#define PROBABILITY 0.9
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+/* for various intercepted calls */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* For builds on glibc */
+#define __USE_GNU
+#include <dlfcn.h>
+
+#include "interrupter.h"
+
+static int probability = PROBABILITY * RAND_MAX;
+
+static int maybe_interrupt() {
+    if (rand() < probability) {
+        return 1;
+    }
+    return 0;
+}
+
+DEFINE_INTERCEPT(read, ssize_t, int, void*, size_t);
+DEFINE_INTERCEPT(write, ssize_t, int, const void*, size_t);
+DEFINE_INTERCEPT(accept, int, int, struct sockaddr*, socklen_t*);
+DEFINE_INTERCEPT(creat, int, const char*, mode_t);
diff --git a/cmds/interrupter/interrupter.h b/cmds/interrupter/interrupter.h
new file mode 100644
index 0000000..9ad0277e
--- /dev/null
+++ b/cmds/interrupter/interrupter.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 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.
+ */
+
+#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
+#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
+#define CONCATENATE2(arg1, arg2)  arg1##arg2
+
+#define INTERRUPTER(sym) \
+    if (real_##sym == NULL) \
+        __init_##sym(); \
+    if (maybe_interrupt()) { \
+        errno = EINTR; \
+        return -1; \
+    }
+
+#define CALL_FUNCTION_1(sym, ret, type1) \
+ret (*real_##sym)(type1) = NULL; \
+ret sym(type1 arg1) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1); \
+}
+
+#define CALL_FUNCTION_2(sym, ret, type1, type2) \
+ret (*real_##sym)(type1, type2) = NULL; \
+ret sym(type1 arg1, type2 arg2) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2); \
+}
+
+#define CALL_FUNCTION_3(sym, ret, type1, type2, type3) \
+ret (*real_##sym)(type1, type2, type3) = NULL; \
+ret sym(type1 arg1, type2 arg2, type3 arg3) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2, arg3); \
+}
+
+#define CALL_FUNCTION_4(sym, ret, type1, type2, type3, type4) \
+ret (*real_##sym)(type1, type2, type3, type4) = NULL; \
+ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2, arg3, arg4); \
+}
+
+#define CALL_FUNCTION_5(sym, ret, type1, type2, type3, type4, type5) \
+ret (*real_##sym)(type1, type2, type3, type4, type5) = NULL; \
+ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
+    INTERRUPTER(sym) \
+    return real_##sym(arg1, arg2, arg3, arg4, arg5); \
+}
+
+#define DEFINE_INTERCEPT_N(N, sym, ret, ...) \
+static void __init_##sym(void); \
+CONCATENATE(CALL_FUNCTION_, N)(sym, ret, __VA_ARGS__) \
+static void __init_##sym(void) { \
+    real_##sym = dlsym(RTLD_NEXT, #sym); \
+    if (real_##sym == NULL) { \
+        fprintf(stderr, "Error hooking " #sym ": %s\n", dlerror()); \
+    } \
+}
+
+#define INTERCEPT_NARG(...) INTERCEPT_NARG_N(__VA_ARGS__, INTERCEPT_RSEQ_N())
+#define INTERCEPT_NARG_N(...) INTERCEPT_ARG_N(__VA_ARGS__)
+#define INTERCEPT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
+#define INTERCEPT_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+#define DEFINE_INTERCEPT(sym, ret, ...) DEFINE_INTERCEPT_N(INTERCEPT_NARG(__VA_ARGS__), sym, ret, __VA_ARGS__)
diff --git a/cmds/media/Android.mk b/cmds/media/Android.mk
new file mode 100644
index 0000000..b9451c5
--- /dev/null
+++ b/cmds/media/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2013 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := media_cmd
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := media
+LOCAL_SRC_FILES := media
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/media/MODULE_LICENSE_APACHE2 b/cmds/media/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/media/MODULE_LICENSE_APACHE2
diff --git a/cmds/media/NOTICE b/cmds/media/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/media/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/cmds/media/media b/cmds/media/media
new file mode 100755
index 0000000..1194442
--- /dev/null
+++ b/cmds/media/media
@@ -0,0 +1,6 @@
+# Script to start "media_cmd" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/media_cmd.jar
+exec app_process $base/bin com.android.commands.media.Media "$@"
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
new file mode 100644
index 0000000..56af7d6
--- /dev/null
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -0,0 +1,220 @@
+/*
+**
+** 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.
+*/
+
+package com.android.commands.media;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.media.IAudioService;
+import android.media.IRemoteControlDisplay;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.AndroidException;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import com.android.internal.os.BaseCommand;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+
+public class Media extends BaseCommand {
+
+    private IAudioService mAudioService;
+
+    /**
+     * Command-line entry point.
+     *
+     * @param args The command-line arguments
+     */
+    public static void main(String[] args) {
+        (new Media()).run(args);
+    }
+
+    public void onShowUsage(PrintStream out) {
+        out.println(
+                "usage: media [subcommand] [options]\n" +
+                "       media dispatch KEY\n" +
+                "       media remote-display\n" +
+                "\n" +
+                "media dispatch: dispatch a media key to the current media client.\n" +
+                "                KEY may be: play, pause, play-pause, mute, headsethook,\n" +
+                "                stop, next, previous, rewind, recordm fast-forword.\n" +
+                "media remote-display: monitor remote display updates.\n"
+        );
+    }
+
+    public void onRun() throws Exception {
+        mAudioService = IAudioService.Stub.asInterface(ServiceManager.checkService(
+                Context.AUDIO_SERVICE));
+        if (mAudioService == null) {
+            System.err.println(NO_SYSTEM_ERROR_CODE);
+            throw new AndroidException("Can't connect to audio service; is the system running?");
+        }
+
+        String op = nextArgRequired();
+
+        if (op.equals("dispatch")) {
+            runDispatch();
+        } else if (op.equals("remote-display")) {
+            runRemoteDisplay();
+        } else {
+            showError("Error: unknown command '" + op + "'");
+            return;
+        }
+    }
+
+    private void sendMediaKey(KeyEvent event) {
+        try {
+            mAudioService.dispatchMediaKeyEvent(event);
+        } catch (RemoteException e) {
+        }
+    }
+
+    private void runDispatch() throws Exception {
+        String cmd = nextArgRequired();
+        int keycode;
+        if ("play".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_PLAY;
+        } else if ("pause".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_PAUSE;
+        } else if ("play-pause".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
+        } else if ("mute".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MUTE;
+        } else if ("headsethook".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_HEADSETHOOK;
+        } else if ("stop".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_STOP;
+        } else if ("next".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_NEXT;
+        } else if ("previous".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
+        } else if ("rewind".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_REWIND;
+        } else if ("record".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_RECORD;
+        } else if ("fast-forward".equals(cmd)) {
+            keycode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD;
+        } else {
+            showError("Error: unknown dispatch code '" + cmd + "'");
+            return;
+        }
+
+        final long now = SystemClock.uptimeMillis();
+        sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0, 0,
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+        sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0, 0,
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
+    }
+
+    class RemoteDisplayMonitor extends IRemoteControlDisplay.Stub {
+        RemoteDisplayMonitor() {
+        }
+
+
+        @Override
+        public void setCurrentClientId(int clientGeneration, PendingIntent clientMediaIntent,
+                boolean clearing) {
+            System.out.println("New client: id=" + clientGeneration
+                    + " intent=" + clientMediaIntent + " clearing=" + clearing);
+        }
+
+        @Override
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
+            System.out.println("New state: id=" + generationId + " state=" + state
+                    + " time=" + stateChangeTimeMs + " pos=" + currentPosMs + " speed=" + speed);
+        }
+
+        @Override
+        public void setTransportControlInfo(int generationId, int transportControlFlags,
+                int posCapabilities) {
+            System.out.println("New control info: id=" + generationId
+                    + " flags=0x" + Integer.toHexString(transportControlFlags)
+                    + " cap=0x" + Integer.toHexString(posCapabilities));
+        }
+
+        @Override
+        public void setMetadata(int generationId, Bundle metadata) {
+            System.out.println("New metadata: id=" + generationId
+                    + " data=" + metadata);
+        }
+
+        @Override
+        public void setArtwork(int generationId, Bitmap artwork) {
+            System.out.println("New artwork: id=" + generationId
+                    + " art=" + artwork);
+        }
+
+        @Override
+        public void setAllMetadata(int generationId, Bundle metadata, Bitmap artwork) {
+            System.out.println("New metadata+artwork: id=" + generationId
+                    + " data=" + metadata + " art=" + artwork);
+        }
+
+        void printUsageMessage() {
+            System.out.println("Monitoring remote control displays...  available commands:");
+            System.out.println("(q)uit: finish monitoring");
+        }
+
+        void run() throws RemoteException {
+            printUsageMessage();
+
+            mAudioService.registerRemoteControlDisplay(this, 0, 0);
+
+            try {
+                InputStreamReader converter = new InputStreamReader(System.in);
+                BufferedReader in = new BufferedReader(converter);
+                String line;
+
+                while ((line = in.readLine()) != null) {
+                    boolean addNewline = true;
+                    if (line.length() <= 0) {
+                        addNewline = false;
+                    } else if ("q".equals(line) || "quit".equals(line)) {
+                        break;
+                    } else {
+                        System.out.println("Invalid command: " + line);
+                    }
+
+                    synchronized (this) {
+                        if (addNewline) {
+                            System.out.println("");
+                        }
+                        printUsageMessage();
+                    }
+                }
+
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                mAudioService.unregisterRemoteControlDisplay(this);
+            }
+        }
+    }
+
+    private void runRemoteDisplay() throws Exception {
+        RemoteDisplayMonitor monitor = new RemoteDisplayMonitor();
+        monitor.run();
+    }
+}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 22ce841..224945a 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1149,10 +1149,7 @@
 
         ClearDataObserver obs = new ClearDataObserver();
         try {
-            if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId)) {
-                System.err.println("Failed");
-            }
-
+            ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId);
             synchronized (obs) {
                 while (!obs.finished) {
                     try {
@@ -1221,7 +1218,8 @@
         ComponentName cn = ComponentName.unflattenFromString(pkg);
         if (cn == null) {
             try {
-                mPm.setApplicationEnabledSetting(pkg, state, 0, userId);
+                mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
+                        "shell:" + android.os.Process.myUid());
                 System.err.println("Package " + pkg + " new state: "
                         + enabledSettingToString(
                         mPm.getApplicationEnabledSetting(pkg, userId)));
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index a1ea81a..be32355 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -23,10 +23,13 @@
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 
-#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+
 #include <gui/SurfaceComposerClient.h>
 #include <gui/ISurfaceComposer.h>
 
+#include <ui/PixelFormat.h>
+
 #include <SkImageEncoder.h>
 #include <SkBitmap.h>
 #include <SkData.h>
@@ -89,6 +92,8 @@
 
 int main(int argc, char** argv)
 {
+    ProcessState::self()->startThreadPool();
+
     const char* pname = argv[0];
     bool png = false;
     int32_t displayId = DEFAULT_DISPLAY_ID;
@@ -135,7 +140,7 @@
     ssize_t mapsize = -1;
 
     void const* base = 0;
-    uint32_t w, h, f;
+    uint32_t w, s, h, f;
     size_t size = 0;
 
     ScreenshotClient screenshot;
@@ -144,6 +149,7 @@
         base = screenshot.getPixels();
         w = screenshot.getWidth();
         h = screenshot.getHeight();
+        s = screenshot.getStride();
         f = screenshot.getFormat();
         size = screenshot.getSize();
     } else {
@@ -157,6 +163,7 @@
                     size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
                     w = vinfo.xres;
                     h = vinfo.yres;
+                    s = vinfo.xres;
                     size = w*h*bytespp;
                     mapsize = offset + size;
                     mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
@@ -172,7 +179,7 @@
     if (base) {
         if (png) {
             SkBitmap b;
-            b.setConfig(flinger2skia(f), w, h);
+            b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f));
             b.setPixels((void*)base);
             SkDynamicMemoryWStream stream;
             SkImageEncoder::EncodeStream(&stream, b,
@@ -184,7 +191,11 @@
             write(fd, &w, 4);
             write(fd, &h, 4);
             write(fd, &f, 4);
-            write(fd, base, size);
+            size_t Bpp = bytesPerPixel(f);
+            for (size_t y=0 ; y<h ; y++) {
+                write(fd, base, w*Bpp);
+                base = (void *)((char *)base + s*Bpp);
+            }
         }
     }
     close(fd);
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index 58105fa..da8586c 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -36,12 +36,18 @@
         return shortHelp() + "\n"
                 + "\n"
                 + "usage: svc power stayon [true|false|usb|ac|wireless]\n"
-                + "         Set the 'keep awake while plugged in' setting.\n";
+                + "         Set the 'keep awake while plugged in' setting.\n"
+                + "       svc power reboot [reason]\n"
+                + "         Perform a runtime shutdown and reboot device with specified reason.\n"
+                + "       svc power shutdown\n"
+                + "         Perform a runtime shutdown and power off the device.\n";
     }
 
     public void run(String[] args) {
         fail: {
             if (args.length >= 2) {
+                IPowerManager pm = IPowerManager.Stub.asInterface(
+                        ServiceManager.getService(Context.POWER_SERVICE));
                 if ("stayon".equals(args[1]) && args.length == 3) {
                     int val;
                     if ("true".equals(args[2])) {
@@ -60,8 +66,6 @@
                     } else {
                         break fail;
                     }
-                    IPowerManager pm
-                            = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
                     try {
                         if (val != 0) {
                             // if the request is not to set it to false, wake up the screen so that
@@ -74,6 +78,26 @@
                         System.err.println("Faild to set setting: " + e);
                     }
                     return;
+                } else if ("reboot".equals(args[1])) {
+                    String mode = null;
+                    if (args.length == 3) {
+                        mode = args[2];
+                    }
+                    try {
+                        // no confirm, wait till device is rebooted
+                        pm.reboot(false, mode, true);
+                    } catch (RemoteException e) {
+                        System.err.println("Failed to reboot.");
+                    }
+                    return;
+                } else if ("shutdown".equals(args[1])) {
+                    try {
+                        // no confirm, wait till device is off
+                        pm.shutdown(false, true);
+                    } catch (RemoteException e) {
+                        System.err.println("Failed to shutdown.");
+                    }
+                    return;
                 }
             }
         }
diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk
index ad537977..3083e31 100644
--- a/cmds/system_server/Android.mk
+++ b/cmds/system_server/Android.mk
@@ -7,7 +7,8 @@
 LOCAL_SHARED_LIBRARIES := \
 	libutils \
 	libbinder \
-	libsystem_server 
+	libsystem_server \
+	liblog
 
 LOCAL_C_INCLUDES := \
 	$(JNI_H_INCLUDE)
@@ -17,4 +18,3 @@
 include $(BUILD_EXECUTABLE)
 
 include $(LOCAL_PATH)/library/Android.mk
-
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index c42424c..d78474e 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -16,10 +16,11 @@
 	libandroid_runtime \
 	libsensorservice \
 	libsurfaceflinger \
-    libinput \
+	libinput \
 	libutils \
 	libbinder \
-	libcutils
+	libcutils \
+	liblog
 
 LOCAL_MODULE:= libsystem_server
 
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index f48764f..815a0ac 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -19,27 +19,22 @@
 package com.android.commands.wm;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.AndroidException;
 import android.view.Display;
 import android.view.IWindowManager;
+import com.android.internal.os.BaseCommand;
 
+import java.io.PrintStream;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class Wm {
+public class Wm extends BaseCommand {
 
     private IWindowManager mWm;
-    private String[] mArgs;
-    private int mNextArg;
-    private String mCurArgData;
-
-    // These are magic strings understood by the Eclipse plugin.
-    private static final String FATAL_ERROR_CODE = "Error type 1";
-    private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
-    private static final String NO_CLASS_ERROR_CODE = "Error type 3";
 
     /**
      * Command-line entry point.
@@ -47,23 +42,25 @@
      * @param args The command-line arguments
      */
     public static void main(String[] args) {
-        try {
-            (new Wm()).run(args);
-        } catch (IllegalArgumentException e) {
-            showUsage();
-            System.err.println("Error: " + e.getMessage());
-        } catch (Exception e) {
-            e.printStackTrace(System.err);
-            System.exit(1);
-        }
+        (new Wm()).run(args);
     }
 
-    private void run(String[] args) throws Exception {
-        if (args.length < 1) {
-            showUsage();
-            return;
-        }
+    public void onShowUsage(PrintStream out) {
+        out.println(
+                "usage: wm [subcommand] [options]\n" +
+                "       wm size [reset|WxH]\n" +
+                "       wm density [reset|DENSITY]\n" +
+                "       wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" +
+                "\n" +
+                "wm size: return or override display size.\n" +
+                "\n" +
+                "wm density: override display density.\n" +
+                "\n" +
+                "wm overscan: set overscan area for display.\n"
+                );
+    }
 
+    public void onRun() throws Exception {
         mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
                         Context.WINDOW_SERVICE));
         if (mWm == null) {
@@ -71,9 +68,7 @@
             throw new AndroidException("Can't connect to window manager; is the system running?");
         }
 
-        mArgs = args;
-        String op = args[0];
-        mNextArg = 1;
+        String op = nextArgRequired();
 
         if (op.equals("size")) {
             runDisplaySize();
@@ -82,14 +77,28 @@
         } else if (op.equals("overscan")) {
             runDisplayOverscan();
         } else {
-            throw new IllegalArgumentException("Unknown command: " + op);
+            showError("Error: unknown command '" + op + "'");
+            return;
         }
     }
 
     private void runDisplaySize() throws Exception {
-        String size = nextArgRequired();
+        String size = nextArg();
         int w, h;
-        if ("reset".equals(size)) {
+        if (size == null) {
+            Point initialSize = new Point();
+            Point baseSize = new Point();
+            try {
+                mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
+                mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
+                System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y);
+                if (!initialSize.equals(baseSize)) {
+                    System.out.println("Override size: " + baseSize.x + "x" + baseSize.y);
+                }
+            } catch (RemoteException e) {
+            }
+            return;
+        } else if ("reset".equals(size)) {
             w = h = -1;
         } else {
             int div = size.indexOf('x');
@@ -120,9 +129,20 @@
     }
 
     private void runDisplayDensity() throws Exception {
-        String densityStr = nextArgRequired();
+        String densityStr = nextArg();
         int density;
-        if ("reset".equals(densityStr)) {
+        if (densityStr == null) {
+            try {
+                int initialDensity = mWm.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
+                int baseDensity = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
+                System.out.println("Physical density: " + initialDensity);
+                if (initialDensity != baseDensity) {
+                    System.out.println("Override density: " + baseDensity);
+                }
+            } catch (RemoteException e) {
+            }
+            return;
+        } else if ("reset".equals(densityStr)) {
             density = -1;
         } else {
             try {
@@ -173,69 +193,4 @@
         } catch (RemoteException e) {
         }
     }
-
-    private String nextOption() {
-        if (mCurArgData != null) {
-            String prev = mArgs[mNextArg - 1];
-            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
-        }
-        if (mNextArg >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mNextArg];
-        if (!arg.startsWith("-")) {
-            return null;
-        }
-        mNextArg++;
-        if (arg.equals("--")) {
-            return null;
-        }
-        if (arg.length() > 1 && arg.charAt(1) != '-') {
-            if (arg.length() > 2) {
-                mCurArgData = arg.substring(2);
-                return arg.substring(0, 2);
-            } else {
-                mCurArgData = null;
-                return arg;
-            }
-        }
-        mCurArgData = null;
-        return arg;
-    }
-
-    private String nextArg() {
-        if (mCurArgData != null) {
-            String arg = mCurArgData;
-            mCurArgData = null;
-            return arg;
-        } else if (mNextArg < mArgs.length) {
-            return mArgs[mNextArg++];
-        } else {
-            return null;
-        }
-    }
-
-    private String nextArgRequired() {
-        String arg = nextArg();
-        if (arg == null) {
-            String prev = mArgs[mNextArg - 1];
-            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
-        }
-        return arg;
-    }
-
-    private static void showUsage() {
-        System.err.println(
-                "usage: wm [subcommand] [options]\n" +
-                "       wm size [reset|WxH]\n" +
-                "       wm density [reset|DENSITY]\n" +
-                "       wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" +
-                "\n" +
-                "wm size: override display size.\n" +
-                "\n" +
-                "wm density: override display density.\n" +
-                "\n" +
-                "wm overscan: set overscan area for display.\n"
-                );
-    }
 }
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index fa46689..dbc9051 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -505,7 +505,6 @@
     }
 
     /**
-     * @hide
      * Returns a Bundle that contains whatever is required to clone the account on a different
      * user. The Bundle is passed to the authenticator instance in the target user via
      * {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}.
@@ -529,7 +528,6 @@
     }
 
     /**
-     * @hide
      * Creates an account based on credentials provided by the authenticator instance of another
      * user on the device, who has chosen to share the account with this user.
      * @param response to send the result back to the AccountManager, will never be null
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 6aac723..241a64a 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -18,9 +18,11 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentFilter;
 import android.content.BroadcastReceiver;
+import android.content.res.Resources;
 import android.database.SQLException;
 import android.os.Bundle;
 import android.os.Handler;
@@ -44,6 +46,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import com.android.internal.R;
 import com.google.android.collect.Maps;
 
 /**
@@ -148,6 +151,10 @@
     public static final int ERROR_CODE_UNSUPPORTED_OPERATION = 6;
     public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
     public static final int ERROR_CODE_BAD_REQUEST = 8;
+    public static final int ERROR_CODE_BAD_AUTHENTICATION = 9;
+
+    /** @hide */
+    public static final int ERROR_CODE_USER_RESTRICTED = 100;
 
     /**
      * Bundle key used for the {@link String} account name in results
@@ -381,6 +388,23 @@
     }
 
     /**
+     * @hide
+     * For use by internal activities. Returns the list of accounts that the calling package
+     * is authorized to use, particularly for shared accounts.
+     * @param packageName package name of the calling app.
+     * @param uid the uid of the calling app.
+     * @return the accounts that are available to this package and user.
+     */
+    public Account[] getAccountsForPackage(String packageName, int uid) {
+        try {
+            return mService.getAccountsForPackage(packageName, uid);
+        } catch (RemoteException re) {
+            // possible security exception
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
      * Lists all accounts of a particular type.  The account type is a
      * string token corresponding to the authenticator and useful domain
      * of the account.  For example, there are types corresponding to Google
@@ -568,7 +592,7 @@
     public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
         if (account == null) throw new IllegalArgumentException("account is null");
         try {
-            return mService.addAccount(account, password, userdata);
+            return mService.addAccountExplicitly(account, password, userdata);
         } catch (RemoteException e) {
             // won't ever happen
             throw new RuntimeException(e);
@@ -958,10 +982,10 @@
      */
     @Deprecated
     public AccountManagerFuture<Bundle> getAuthToken(
-            final Account account, final String authTokenType, 
+            final Account account, final String authTokenType,
             final boolean notifyAuthFailure,
             AccountManagerCallback<Bundle> callback, Handler handler) {
-        return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback, 
+        return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback,
                 handler);
     }
 
@@ -1116,7 +1140,7 @@
 
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
-                mService.addAcount(mResponse, accountType, authTokenType,
+                mService.addAccount(mResponse, accountType, authTokenType,
                         requiredFeatures, activity != null, optionsIn);
             }
         }.start();
@@ -1523,7 +1547,7 @@
             }
 
             public void onError(int code, String message) {
-                if (code == ERROR_CODE_CANCELED) {
+                if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED) {
                     // the authenticator indicated that this request was canceled, do so now
                     cancel(true /* mayInterruptIfRunning */);
                     return;
@@ -1777,8 +1801,11 @@
                                     };
                                     // have many accounts, launch the chooser
                                     Intent intent = new Intent();
-                                    intent.setClassName("android",
-                                            "android.accounts.ChooseAccountActivity");
+                                    ComponentName componentName = ComponentName.unflattenFromString(
+                                            Resources.getSystem().getString(
+                                                    R.string.config_chooseAccountActivity));
+                                    intent.setClassName(componentName.getPackageName(),
+                                            componentName.getClassName());
                                     intent.putExtra(KEY_ACCOUNTS, accounts);
                                     intent.putExtra(KEY_ACCOUNT_MANAGER_RESPONSE,
                                             new AccountManagerResponse(chooseResponse));
@@ -1904,7 +1931,7 @@
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
-     * <pre>  newChooseAccountsIntent(null, null, new String[]{"com.google"}, false, null,
+     * <pre>  newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
      * null, null, null);</pre>
      * @param selectedAccount if specified, indicates that the {@link Account} is the currently
      * selected one, according to the caller's definition of selected.
@@ -1934,7 +1961,10 @@
             String[] addAccountRequiredFeatures,
             Bundle addAccountOptions) {
         Intent intent = new Intent();
-        intent.setClassName("android", "android.accounts.ChooseTypeAndAccountActivity");
+        ComponentName componentName = ComponentName.unflattenFromString(
+                Resources.getSystem().getString(R.string.config_chooseTypeAndAccountActivity));
+        intent.setClassName(componentName.getPackageName(),
+                componentName.getClassName());
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNTS_ARRAYLIST,
                 allowableAccounts);
         intent.putExtra(ChooseTypeAndAccountActivity.EXTRA_ALLOWABLE_ACCOUNT_TYPES_STRING_ARRAY,
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 5358bc7..2aba163 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -18,9 +18,14 @@
 import com.google.android.collect.Sets;
 
 import android.app.Activity;
+import android.app.ActivityManagerNative;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -29,6 +34,7 @@
 import android.widget.Button;
 import android.widget.ListView;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.internal.R;
 
@@ -119,6 +125,9 @@
     private Parcelable[] mExistingAccounts = null;
     private int mSelectedItemIndex;
     private Button mOkButton;
+    private int mCallingUid;
+    private String mCallingPackage;
+    private boolean mDisallowAddAccounts;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -128,6 +137,24 @@
                     + savedInstanceState + ")");
         }
 
+        String message = null;
+
+        try {
+            IBinder activityToken = getActivityToken();
+            mCallingUid = ActivityManagerNative.getDefault().getLaunchedFromUid(activityToken);
+            mCallingPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+                    activityToken);
+            if (mCallingUid != 0 && mCallingPackage != null) {
+                Bundle restrictions = UserManager.get(this)
+                        .getUserRestrictions(new UserHandle(UserHandle.getUserId(mCallingUid)));
+                mDisallowAddAccounts =
+                        restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false);
+            }
+        } catch (RemoteException re) {
+            // Couldn't figure out caller details
+            Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
+        }
+
         // save some items we use frequently
         final Intent intent = getIntent();
 
@@ -179,6 +206,11 @@
             // If there are no relevant accounts and only one relevant account type go directly to
             // add account. Otherwise let the user choose.
             if (mAccounts.isEmpty()) {
+                if (mDisallowAddAccounts) {
+                    setContentView(R.layout.app_not_authorized);
+                    setTitle(R.string.error_message_title);
+                    return;
+                }
                 if (mSetOfRelevantAccountTypes.size() == 1) {
                     runAddAccountForAuthenticator(mSetOfRelevantAccountTypes.iterator().next());
                 } else {
@@ -296,7 +328,8 @@
                 }
 
                 if (accountName == null || accountType == null) {
-                    Account[] currentAccounts = AccountManager.get(this).getAccounts();
+                    Account[] currentAccounts = AccountManager.get(this).getAccountsForPackage(
+                            mCallingPackage, mCallingUid);
                     Set<Account> preExistingAccounts = new HashSet<Account>();
                     for (Parcelable accountParcel : mExistingAccounts) {
                         preExistingAccounts.add((Account) accountParcel);
@@ -347,7 +380,8 @@
                     AccountManager.KEY_INTENT);
             if (intent != null) {
                 mPendingRequest = REQUEST_ADD_ACCOUNT;
-                mExistingAccounts = AccountManager.get(this).getAccounts();
+                mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
+                        mCallingUid);
                 intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
                 startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
                 return;
@@ -424,12 +458,14 @@
     private String[] getListOfDisplayableOptions(ArrayList<Account> accounts) {
       // List of options includes all accounts found together with "Add new account" as the
       // last item in the list.
-      String[] listItems = new String[accounts.size() + 1];
+      String[] listItems = new String[accounts.size() + (mDisallowAddAccounts ? 0 : 1)];
       for (int i = 0; i < accounts.size(); i++) {
           listItems[i] = accounts.get(i).name;
       }
-      listItems[accounts.size()] = getResources().getString(
-              R.string.add_account_button_label);
+      if (!mDisallowAddAccounts) {
+          listItems[accounts.size()] = getResources().getString(
+                  R.string.add_account_button_label);
+      }
       return listItems;
     }
 
@@ -439,7 +475,8 @@
      * allowable accounts, if provided.
      */
     private ArrayList<Account> getAcceptableAccountChoices(AccountManager accountManager) {
-      final Account[] accounts = accountManager.getAccounts();
+      final Account[] accounts = accountManager.getAccountsForPackage(mCallingPackage,
+              mCallingUid);
       ArrayList<Account> accountsToPopulate = new ArrayList<Account>(accounts.length);
       for (Account account : accounts) {
           if (mSetOfAllowableAccounts != null
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 47b257d..8141813 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -31,10 +31,11 @@
     String getUserData(in Account account, String key);
     AuthenticatorDescription[] getAuthenticatorTypes();
     Account[] getAccounts(String accountType);
+    Account[] getAccountsForPackage(String packageName, int uid);
     Account[] getAccountsAsUser(String accountType, int userId);
     void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features);
     void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
-    boolean addAccount(in Account account, String password, in Bundle extras);
+    boolean addAccountExplicitly(in Account account, String password, in Bundle extras);
     void removeAccount(in IAccountManagerResponse response, in Account account);
     void invalidateAuthToken(String accountType, String authToken);
     String peekAuthToken(in Account account, String authTokenType);
@@ -47,7 +48,7 @@
     void getAuthToken(in IAccountManagerResponse response, in Account account,
         String authTokenType, boolean notifyOnAuthFailure, boolean expectActivityLaunch,
         in Bundle options);
-    void addAcount(in IAccountManagerResponse response, String accountType,
+    void addAccount(in IAccountManagerResponse response, String accountType,
         String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,
         in Bundle options);
     void updateCredentials(in IAccountManagerResponse response, in Account account,
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index ed4036d..d753e32 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -185,7 +185,7 @@
         TypedArray a =
                 context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator);
 
-        long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 0);
+        long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300);
 
         long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0);
 
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 6172aab..4026f7f 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -21,6 +21,7 @@
 import android.animation.Keyframe.IntKeyframe;
 import android.animation.Keyframe.FloatKeyframe;
 import android.animation.Keyframe.ObjectKeyframe;
+import android.util.Log;
 
 /**
  * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
@@ -56,24 +57,36 @@
         } else {
             keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
             for (int i = 1; i < numKeyframes; ++i) {
-                keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
+                keyframes[i] =
+                        (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
             }
         }
         return new IntKeyframeSet(keyframes);
     }
 
     public static KeyframeSet ofFloat(float... values) {
+        boolean badValue = false;
         int numKeyframes = values.length;
         FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
         if (numKeyframes == 1) {
             keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
             keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
+            if (Float.isNaN(values[0])) {
+                badValue = true;
+            }
         } else {
             keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
             for (int i = 1; i < numKeyframes; ++i) {
-                keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
+                keyframes[i] =
+                        (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
+                if (Float.isNaN(values[i])) {
+                    badValue = true;
+                }
             }
         }
+        if (badValue) {
+            Log.w("Animator", "Bad value (NaN) in float animator");
+        }
         return new FloatKeyframeSet(keyframes);
     }
 
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 0372cb0..173ee73 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -19,7 +19,6 @@
 import android.util.Log;
 import android.util.Property;
 
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 
 /**
@@ -49,6 +48,8 @@
 
     private Property mProperty;
 
+    private boolean mAutoCancel = false;
+
     /**
      * Sets the name of the property that will be animated. This name is used to derive
      * a setter function that will be called to set animated values.
@@ -346,17 +347,83 @@
             // No values yet - this animator is being constructed piecemeal. Init the values with
             // whatever the current propertyName is
             if (mProperty != null) {
-                setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values));
+                setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator) null, values));
             } else {
-                setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values));
+                setValues(PropertyValuesHolder.ofObject(mPropertyName,
+                        (TypeEvaluator) null, values));
             }
         } else {
             super.setObjectValues(values);
         }
     }
 
+    /**
+     * autoCancel controls whether an ObjectAnimator will be canceled automatically
+     * when any other ObjectAnimator with the same target and properties is started.
+     * Setting this flag may make it easier to run different animators on the same target
+     * object without having to keep track of whether there are conflicting animators that
+     * need to be manually canceled. Canceling animators must have the same exact set of
+     * target properties, in the same order.
+     *
+     * @param cancel Whether future ObjectAnimators with the same target and properties
+     * as this ObjectAnimator will cause this ObjectAnimator to be canceled.
+     */
+    public void setAutoCancel(boolean cancel) {
+        mAutoCancel = cancel;
+    }
+
+    private boolean hasSameTargetAndProperties(Animator anim) {
+        if (anim instanceof ObjectAnimator) {
+            PropertyValuesHolder[] theirValues = ((ObjectAnimator) anim).getValues();
+            if (((ObjectAnimator) anim).getTarget() == mTarget &&
+                    mValues.length == theirValues.length) {
+                for (int i = 0; i < mValues.length; ++i) {
+                    PropertyValuesHolder pvhMine = mValues[i];
+                    PropertyValuesHolder pvhTheirs = theirValues[i];
+                    if (pvhMine.getPropertyName() == null ||
+                            !pvhMine.getPropertyName().equals(pvhTheirs.getPropertyName())) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public void start() {
+        // See if any of the current active/pending animators need to be canceled
+        AnimationHandler handler = sAnimationHandler.get();
+        if (handler != null) {
+            int numAnims = handler.mAnimations.size();
+            for (int i = numAnims - 1; i >= 0; i--) {
+                if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
+                    ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
+                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
+                        anim.cancel();
+                    }
+                }
+            }
+            numAnims = handler.mPendingAnimations.size();
+            for (int i = numAnims - 1; i >= 0; i--) {
+                if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
+                    ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
+                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
+                        anim.cancel();
+                    }
+                }
+            }
+            numAnims = handler.mDelayedAnims.size();
+            for (int i = numAnims - 1; i >= 0; i--) {
+                if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
+                    ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
+                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
+                        anim.cancel();
+                    }
+                }
+            }
+        }
         if (DBG) {
             Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
             for (int i = 0; i < mValues.length; ++i) {
diff --git a/core/java/android/animation/RectEvaluator.java b/core/java/android/animation/RectEvaluator.java
new file mode 100644
index 0000000..28d496b
--- /dev/null
+++ b/core/java/android/animation/RectEvaluator.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+import android.graphics.Rect;
+
+/**
+ * This evaluator can be used to perform type interpolation between <code>Rect</code> values.
+ */
+public class RectEvaluator implements TypeEvaluator<Rect> {
+
+    /**
+     * This function returns the result of linearly interpolating the start and
+     * end Rect values, with <code>fraction</code> representing the proportion
+     * between the start and end values. The calculation is a simple parametric
+     * calculation on each of the separate components in the Rect objects
+     * (left, top, right, and bottom).
+     *
+     * @param fraction   The fraction from the starting to the ending values
+     * @param startValue The start Rect
+     * @param endValue   The end Rect
+     * @return A linear interpolation between the start and end values, given the
+     *         <code>fraction</code> parameter.
+     */
+    @Override
+    public Rect evaluate(float fraction, Rect startValue, Rect endValue) {
+        return new Rect(startValue.left + (int)((endValue.left - startValue.left) * fraction),
+                startValue.top + (int)((endValue.top - startValue.top) * fraction),
+                startValue.right + (int)((endValue.right - startValue.right) * fraction),
+                startValue.bottom + (int)((endValue.bottom - startValue.bottom) * fraction));
+    }
+}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f7460c4..ea605b9 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -83,7 +83,10 @@
 
     // The static sAnimationHandler processes the internal timing loop on which all animations
     // are based
-    private static ThreadLocal<AnimationHandler> sAnimationHandler =
+    /**
+     * @hide
+     */
+    protected static ThreadLocal<AnimationHandler> sAnimationHandler =
             new ThreadLocal<AnimationHandler>();
 
     // The time interpolator to be used if none is set on the animation
@@ -531,22 +534,27 @@
      * animations possible.
      *
      * The handler uses the Choreographer for executing periodic callbacks.
+     *
+     * @hide
      */
-    private static class AnimationHandler implements Runnable {
+    protected static class AnimationHandler implements Runnable {
         // The per-thread list of all active animations
-        private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
+        /** @hide */
+        protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
 
         // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
         private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
 
         // The per-thread set of animations to be started on the next animation frame
-        private final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
+        /** @hide */
+        protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
 
         /**
          * Internal per-thread collections used to avoid set collisions as animations start and end
          * while being processed.
+         * @hide
          */
-        private final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
+        protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
         private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
         private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
 
@@ -1015,6 +1023,7 @@
         mRunning = false;
         mStarted = false;
         mStartListenersCalled = false;
+        mPlayingBackwards = false;
     }
 
     /**
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3602fc4..c4ddf1f 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -695,6 +695,86 @@
     public boolean isTitleTruncated() { return false; }
 
     /**
+     * Set an alternate drawable to display next to the icon/logo/title
+     * when {@link #DISPLAY_HOME_AS_UP} is enabled. This can be useful if you are using
+     * this mode to display an alternate selection for up navigation, such as a sliding drawer.
+     *
+     * <p>If you pass <code>null</code> to this method, the default drawable from the theme
+     * will be used.</p>
+     *
+     * <p>If you implement alternate or intermediate behavior around Up, you should also
+     * call {@link #setHomeActionContentDescription(int) setHomeActionContentDescription()}
+     * to provide a correct description of the action for accessibility support.</p>
+     *
+     * @param indicator A drawable to use for the up indicator, or null to use the theme's default
+     *
+     * @see #setDisplayOptions(int, int)
+     * @see #setDisplayHomeAsUpEnabled(boolean)
+     * @see #setHomeActionContentDescription(int)
+     */
+    public void setHomeAsUpIndicator(Drawable indicator) { }
+
+    /**
+     * Set an alternate drawable to display next to the icon/logo/title
+     * when {@link #DISPLAY_HOME_AS_UP} is enabled. This can be useful if you are using
+     * this mode to display an alternate selection for up navigation, such as a sliding drawer.
+     *
+     * <p>If you pass <code>0</code> to this method, the default drawable from the theme
+     * will be used.</p>
+     *
+     * <p>If you implement alternate or intermediate behavior around Up, you should also
+     * call {@link #setHomeActionContentDescription(int) setHomeActionContentDescription()}
+     * to provide a correct description of the action for accessibility support.</p>
+     *
+     * @param resId Resource ID of a drawable to use for the up indicator, or null
+     *              to use the theme's default
+     *
+     * @see #setDisplayOptions(int, int)
+     * @see #setDisplayHomeAsUpEnabled(boolean)
+     * @see #setHomeActionContentDescription(int)
+     */
+    public void setHomeAsUpIndicator(int resId) { }
+
+    /**
+     * Set an alternate description for the Home/Up action, when enabled.
+     *
+     * <p>This description is commonly used for accessibility/screen readers when
+     * the Home action is enabled. (See {@link #setDisplayHomeAsUpEnabled(boolean)}.)
+     * Examples of this are, "Navigate Home" or "Navigate Up" depending on the
+     * {@link #DISPLAY_HOME_AS_UP} display option. If you have changed the home-as-up
+     * indicator using {@link #setHomeAsUpIndicator(int)} to indicate more specific
+     * functionality such as a sliding drawer, you should also set this to accurately
+     * describe the action.</p>
+     *
+     * <p>Setting this to <code>null</code> will use the system default description.</p>
+     *
+     * @param description New description for the Home action when enabled
+     * @see #setHomeAsUpIndicator(int)
+     * @see #setHomeAsUpIndicator(android.graphics.drawable.Drawable)
+     */
+    public void setHomeActionContentDescription(CharSequence description) { }
+
+    /**
+     * Set an alternate description for the Home/Up action, when enabled.
+     *
+     * <p>This description is commonly used for accessibility/screen readers when
+     * the Home action is enabled. (See {@link #setDisplayHomeAsUpEnabled(boolean)}.)
+     * Examples of this are, "Navigate Home" or "Navigate Up" depending on the
+     * {@link #DISPLAY_HOME_AS_UP} display option. If you have changed the home-as-up
+     * indicator using {@link #setHomeAsUpIndicator(int)} to indicate more specific
+     * functionality such as a sliding drawer, you should also set this to accurately
+     * describe the action.</p>
+     *
+     * <p>Setting this to <code>0</code> will use the system default description.</p>
+     *
+     * @param resId Resource ID of a string to use as the new description
+     *              for the Home action when enabled
+     * @see #setHomeAsUpIndicator(int)
+     * @see #setHomeAsUpIndicator(android.graphics.drawable.Drawable)
+     */
+    public void setHomeActionContentDescription(int resId) { }
+
+    /**
      * Listener interface for ActionBar navigation events.
      */
     public interface OnNavigationListener {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 87c2d8c..31074e2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3513,7 +3513,8 @@
         try {
             String resolvedType = null;
             if (fillInIntent != null) {
-                fillInIntent.setAllowFds(false);
+                fillInIntent.migrateExtraStreamToClipData();
+                fillInIntent.prepareToLeaveProcess();
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -3738,7 +3739,8 @@
         if (mParent == null) {
             int result = ActivityManager.START_RETURN_INTENT_TO_CALLER;
             try {
-                intent.setAllowFds(false);
+                intent.migrateExtraStreamToClipData();
+                intent.prepareToLeaveProcess();
                 result = ActivityManagerNative.getDefault()
                     .startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
                             intent, intent.resolveTypeIfNeeded(getContentResolver()),
@@ -3808,7 +3810,8 @@
     public boolean startNextMatchingActivity(Intent intent, Bundle options) {
         if (mParent == null) {
             try {
-                intent.setAllowFds(false);
+                intent.migrateExtraStreamToClipData();
+                intent.prepareToLeaveProcess();
                 return ActivityManagerNative.getDefault()
                     .startNextMatchingActivity(mToken, intent, options);
             } catch (RemoteException e) {
@@ -4162,7 +4165,7 @@
             if (false) Log.v(TAG, "Finishing self: token=" + mToken);
             try {
                 if (resultData != null) {
-                    resultData.setAllowFds(false);
+                    resultData.prepareToLeaveProcess();
                 }
                 if (ActivityManagerNative.getDefault()
                     .finishActivity(mToken, resultCode, resultData)) {
@@ -4314,7 +4317,7 @@
             int flags) {
         String packageName = getPackageName();
         try {
-            data.setAllowFds(false);
+            data.prepareToLeaveProcess();
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                         ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
@@ -4993,9 +4996,10 @@
                 resultData = mResultData;
             }
             if (resultData != null) {
-                resultData.setAllowFds(false);
+                resultData.prepareToLeaveProcess();
             }
             try {
+                upIntent.prepareToLeaveProcess();
                 return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
                         resultCode, resultData);
             } catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 944a533..bb9e19f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -896,7 +896,7 @@
      * @param taskId The identifier of the task to be moved, as found in
      * {@link RunningTaskInfo} or {@link RecentTaskInfo}.
      * @param flags Additional operational flags, 0 or more of
-     * {@link #MOVE_TASK_WITH_HOME}.
+     * {@link #MOVE_TASK_WITH_HOME}, {@link #MOVE_TASK_NO_USER_ACTION}.
      */
     public void moveTaskToFront(int taskId, int flags) {
         moveTaskToFront(taskId, flags, null);
@@ -911,7 +911,7 @@
      * @param taskId The identifier of the task to be moved, as found in
      * {@link RunningTaskInfo} or {@link RecentTaskInfo}.
      * @param flags Additional operational flags, 0 or more of
-     * {@link #MOVE_TASK_WITH_HOME}.
+     * {@link #MOVE_TASK_WITH_HOME}, {@link #MOVE_TASK_NO_USER_ACTION}.
      * @param options Additional options for the operation, either null or
      * as per {@link Context#startActivity(Intent, android.os.Bundle)
      * Context.startActivity(Intent, Bundle)}.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index aca4f9c..c99051b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1853,6 +1853,15 @@
             return true;
         }
 
+        case KILL_UID_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int uid = data.readInt();
+            String reason = data.readString();
+            killUid(uid, reason);
+            reply.writeNoException();
+            return true;
+        }
+
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3335,6 +3344,7 @@
         data.writeString(reason);
         data.writeInt(secure ? 1 : 0);
         mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
+        reply.readException();
         boolean res = reply.readInt() != 0;
         data.recycle();
         reply.recycle();
@@ -4229,5 +4239,17 @@
         reply.recycle();
     }
 
+    public void killUid(int uid, String reason) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(uid);
+        data.writeString(reason);
+        mRemote.transact(KILL_UID_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bb73cf4..e6ce963 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -86,6 +86,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.renderscript.RenderScript;
+import android.security.AndroidKeyStoreProvider;
 
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.RuntimeInit;
@@ -101,6 +102,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.net.InetAddress;
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -4320,6 +4322,10 @@
             GLUtils.setTracingLevel(1);
         }
 
+        // Allow application-generated systrace messages if we're debuggable.
+        boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+        Trace.setAppTracingAllowed(appTracingAllowed);
+
         /**
          * Initialize the default http proxy in this process for the reasons we set the time zone.
          */
@@ -4533,6 +4539,8 @@
                                 + "snatched provider from the jaws of death");
                     }
                     prc.removePending = false;
+                    // There is a race! It fails to remove the message, which
+                    // will be handled in completeRemoveProvider().
                     mH.removeMessages(H.REMOVE_PROVIDER, prc);
                 } else {
                     unstableDelta = 0;
@@ -4712,6 +4720,11 @@
                 return;
             }
 
+            // More complicated race!! Some client managed to acquire the
+            // provider and release it before the removal was completed.
+            // Continue the removal, and abort the next remove message.
+            prc.removePending = false;
+
             final IBinder jBinder = prc.holder.provider.asBinder();
             ProviderRefCount existingPrc = mProviderRefCountMap.get(jBinder);
             if (existingPrc == prc) {
@@ -5061,6 +5074,8 @@
         // Set the reporter for event logging in libcore
         EventLogger.setReporter(new EventLoggingReporter());
 
+        Security.addProvider(new AndroidKeyStoreProvider());
+
         Process.setArgV0("<pre-initialized>");
 
         Looper.prepareMainLooper();
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 132388e..7b07438 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -17,14 +17,17 @@
 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
@@ -131,6 +134,11 @@
         }
     }
 
+    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);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6d55dd5..271494f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1279,7 +1279,8 @@
     public void setApplicationEnabledSetting(String packageName,
                                              int newState, int flags) {
         try {
-            mPM.setApplicationEnabledSetting(packageName, newState, flags, mContext.getUserId());
+            mPM.setApplicationEnabledSetting(packageName, newState, flags,
+                    mContext.getUserId(), mContext.getBasePackageName());
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 734d435..19d495b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -19,7 +19,7 @@
 import com.android.internal.policy.PolicyManager;
 import com.android.internal.util.Preconditions;
 
-import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -319,7 +319,7 @@
 
         registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    return BluetoothAdapter.getDefaultAdapter();
+                    return new BluetoothManager(ctx);
                 }});
 
         registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
@@ -371,9 +371,9 @@
                     return new DisplayManager(ctx.getOuterContext());
                 }});
 
-        registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return InputMethodManager.getInstance(ctx);
+        registerService(INPUT_METHOD_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    return InputMethodManager.getInstance();
                 }});
 
         registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
@@ -1020,7 +1020,8 @@
         try {
             String resolvedType = null;
             if (fillInIntent != null) {
-                fillInIntent.setAllowFds(false);
+                fillInIntent.migrateExtraStreamToClipData();
+                fillInIntent.prepareToLeaveProcess();
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -1040,7 +1041,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
@@ -1054,7 +1055,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,
@@ -1068,7 +1069,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,
@@ -1083,7 +1084,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, true, false,
@@ -1126,7 +1127,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermission, appOp,
@@ -1139,7 +1140,7 @@
     public void sendBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
                     intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
                     AppOpsManager.OP_NONE, false, false, user.getIdentifier());
@@ -1152,7 +1153,7 @@
             String receiverPermission) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, false, false,
@@ -1184,7 +1185,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermission,
@@ -1198,7 +1199,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true,
@@ -1232,7 +1233,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
@@ -1249,7 +1250,7 @@
             intent.setDataAndType(intent.getData(), resolvedType);
         }
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().unbroadcastIntent(
                     mMainThread.getApplicationThread(), intent, getUserId());
         } catch (RemoteException e) {
@@ -1260,7 +1261,7 @@
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, user.getIdentifier());
@@ -1292,7 +1293,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
@@ -1309,7 +1310,7 @@
             intent.setDataAndType(intent.getData(), resolvedType);
         }
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().unbroadcastIntent(
                     mMainThread.getApplicationThread(), intent, user.getIdentifier());
         } catch (RemoteException e) {
@@ -1393,7 +1394,7 @@
     @Override
     public ComponentName startServiceAsUser(Intent service, UserHandle user) {
         try {
-            service.setAllowFds(false);
+            service.prepareToLeaveProcess();
             ComponentName cn = ActivityManagerNative.getDefault().startService(
                 mMainThread.getApplicationThread(), service,
                 service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1417,7 +1418,7 @@
     @Override
     public boolean stopServiceAsUser(Intent service, UserHandle user) {
         try {
-            service.setAllowFds(false);
+            service.prepareToLeaveProcess();
             int res = ActivityManagerNative.getDefault().stopService(
                 mMainThread.getApplicationThread(), service,
                 service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1459,7 +1460,7 @@
                     < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                 flags |= BIND_WAIVE_PRIORITY;
             }
-            service.setAllowFds(false);
+            service.prepareToLeaveProcess();
             int res = ActivityManagerNative.getDefault().bindService(
                 mMainThread.getApplicationThread(), getActivityToken(),
                 service, service.resolveTypeIfNeeded(getContentResolver()),
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 26dc60d..165c3db 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -461,39 +461,63 @@
         }
 
         /**
-         * Set the local destination for the downloaded file to a path within the application's
-         * external files directory (as returned by {@link Context#getExternalFilesDir(String)}.
+         * Set the local destination for the downloaded file to a path within
+         * the application's external files directory (as returned by
+         * {@link Context#getExternalFilesDir(String)}.
          * <p>
-         * The downloaded file is not scanned by MediaScanner.
-         * But it can be made scannable by calling {@link #allowScanningByMediaScanner()}.
+         * The downloaded file is not scanned by MediaScanner. But it can be
+         * made scannable by calling {@link #allowScanningByMediaScanner()}.
          *
-         * @param context the {@link Context} to use in determining the external files directory
-         * @param dirType the directory type to pass to {@link Context#getExternalFilesDir(String)}
-         * @param subPath the path within the external directory, including the destination filename
+         * @param context the {@link Context} to use in determining the external
+         *            files directory
+         * @param dirType the directory type to pass to
+         *            {@link Context#getExternalFilesDir(String)}
+         * @param subPath the path within the external directory, including the
+         *            destination filename
          * @return this object
+         * @throws IllegalStateException If the external storage directory
+         *             cannot be found or created.
          */
         public Request setDestinationInExternalFilesDir(Context context, String dirType,
                 String subPath) {
-            setDestinationFromBase(context.getExternalFilesDir(dirType), subPath);
+            final File file = context.getExternalFilesDir(dirType);
+            if (file == null) {
+                throw new IllegalStateException("Failed to get external storage files directory");
+            } else if (file.exists()) {
+                if (!file.isDirectory()) {
+                    throw new IllegalStateException(file.getAbsolutePath() +
+                            " already exists and is not a directory");
+                }
+            } else {
+                if (!file.mkdirs()) {
+                    throw new IllegalStateException("Unable to create directory: "+
+                            file.getAbsolutePath());
+                }
+            }
+            setDestinationFromBase(file, subPath);
             return this;
         }
 
         /**
-         * Set the local destination for the downloaded file to a path within the public external
-         * storage directory (as returned by
-         * {@link Environment#getExternalStoragePublicDirectory(String)}.
-         *<p>
-         * The downloaded file is not scanned by MediaScanner.
-         * But it can be made scannable by calling {@link #allowScanningByMediaScanner()}.
+         * Set the local destination for the downloaded file to a path within
+         * the public external storage directory (as returned by
+         * {@link Environment#getExternalStoragePublicDirectory(String)}).
+         * <p>
+         * The downloaded file is not scanned by MediaScanner. But it can be
+         * made scannable by calling {@link #allowScanningByMediaScanner()}.
          *
-         * @param dirType the directory type to pass to
-         *        {@link Environment#getExternalStoragePublicDirectory(String)}
-         * @param subPath the path within the external directory, including the destination filename
+         * @param dirType the directory type to pass to {@link Environment#getExternalStoragePublicDirectory(String)}
+         * @param subPath the path within the external directory, including the
+         *            destination filename
          * @return this object
+         * @throws IllegalStateException If the external storage directory
+         *             cannot be found or created.
          */
         public Request setDestinationInExternalPublicDir(String dirType, String subPath) {
             File file = Environment.getExternalStoragePublicDirectory(dirType);
-            if (file.exists()) {
+            if (file == null) {
+                throw new IllegalStateException("Failed to get external storage public directory");
+            } else if (file.exists()) {
                 if (!file.isDirectory()) {
                     throw new IllegalStateException(file.getAbsolutePath() +
                             " already exists and is not a directory");
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index cf4c729..fa8839a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -373,6 +373,8 @@
 
     public void reportTopActivityExtras(IBinder token, Bundle extras) throws RemoteException;
 
+    public void killUid(int uid, String reason) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -632,4 +634,5 @@
     int GET_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+161;
     int REPORT_TOP_ACTIVITY_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+162;
     int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163;
+    int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
 }
diff --git a/core/java/android/app/INotificationListener.aidl b/core/java/android/app/INotificationListener.aidl
deleted file mode 100644
index f010a2a..0000000
--- a/core/java/android/app/INotificationListener.aidl
+++ /dev/null
@@ -1,26 +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.app;
-
-import com.android.internal.statusbar.StatusBarNotification;
-
-/** @hide */
-oneway interface INotificationListener
-{
-    void onNotificationPosted(in StatusBarNotification notification);
-    void onNotificationRemoved(in StatusBarNotification notification);
-}
\ No newline at end of file
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 14bcc0d..92ec3ad 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -17,12 +17,12 @@
 
 package android.app;
 
-import android.app.INotificationListener;
 import android.app.ITransientNotification;
+import android.service.notification.StatusBarNotification;
 import android.app.Notification;
+import android.content.ComponentName;
 import android.content.Intent;
-
-import com.android.internal.statusbar.StatusBarNotification;
+import android.service.notification.INotificationListener;
 
 /** {@hide} */
 interface INotificationManager
@@ -41,7 +41,9 @@
     StatusBarNotification[] getActiveNotifications(String callingPkg);
     StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
 
-    void registerListener(in INotificationListener listener, int userid);
+    void registerListener(in INotificationListener listener, in ComponentName component, int userid);
     void unregisterListener(in INotificationListener listener, int userid);
-}
 
+    void clearNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
+    void clearAllNotificationsFromListener(in INotificationListener token);
+}
\ No newline at end of file
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e7bf305..e0dfb25 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1410,8 +1410,8 @@
             }
         }
         try {
-            intent.setAllowFds(false);
             intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1467,7 +1467,8 @@
         try {
             String[] resolvedTypes = new String[intents.length];
             for (int i=0; i<intents.length; i++) {
-                intents[i].setAllowFds(false);
+                intents[i].migrateExtraStreamToClipData();
+                intents[i].prepareToLeaveProcess();
                 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -1526,8 +1527,8 @@
             }
         }
         try {
-            intent.setAllowFds(false);
             intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1586,8 +1587,8 @@
             }
         }
         try {
-            intent.setAllowFds(false);
             intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
             int result = ActivityManagerNative.getDefault()
                 .startActivityAsUser(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index a1a147a..7e0a27a 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -123,13 +123,13 @@
 
         if (mToggleMode) {
             if (mRemoteActive) {
-                mRouter.selectRouteInt(mRouteTypes, mRouter.getSystemAudioRoute());
+                mRouter.selectRouteInt(mRouteTypes, mRouter.getDefaultRoute());
             } else {
                 final int N = mRouter.getRouteCount();
                 for (int i = 0; i < N; i++) {
                     final RouteInfo route = mRouter.getRouteAt(i);
                     if ((route.getSupportedTypes() & mRouteTypes) != 0 &&
-                            route != mRouter.getSystemAudioRoute()) {
+                            route != mRouter.getDefaultRoute()) {
                         mRouter.selectRouteInt(mRouteTypes, route);
                     }
                 }
@@ -216,7 +216,7 @@
 
     void updateRemoteIndicator() {
         final RouteInfo selected = mRouter.getSelectedRoute(mRouteTypes);
-        final boolean isRemote = selected != mRouter.getSystemAudioRoute();
+        final boolean isRemote = selected != mRouter.getDefaultRoute();
         final boolean isConnecting = selected != null &&
                 selected.getStatusCode() == RouteInfo.STATUS_CONNECTING;
 
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 396f910..7d8a36e 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -1,7 +1,20 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package android.app;
 
-import com.android.internal.view.IInputMethodSession;
-
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -25,7 +38,6 @@
 import android.view.inputmethod.InputMethodManager;
 
 import java.io.File;
-import java.lang.ref.WeakReference;
 
 /**
  * Convenience for implementing an activity that will be implemented
@@ -65,7 +77,6 @@
 
     private NativeContentView mNativeContentView;
     private InputMethodManager mIMM;
-    private InputMethodCallback mInputMethodCallback;
 
     private int mNativeHandle;
     
@@ -117,22 +128,6 @@
             super(context, attrs);
         }
     }
-    
-    static final class InputMethodCallback implements InputMethodManager.FinishedEventCallback {
-        WeakReference<NativeActivity> mNa;
-
-        InputMethodCallback(NativeActivity na) {
-            mNa = new WeakReference<NativeActivity>(na);
-        }
-
-        @Override
-        public void finishedEvent(int seq, boolean handled) {
-            NativeActivity na = mNa.get();
-            if (na != null) {
-                na.finishPreDispatchKeyEventNative(na.mNativeHandle, seq, handled);
-            }
-        }
-    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -141,7 +136,6 @@
         ActivityInfo ai;
         
         mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
-        mInputMethodCallback = new InputMethodCallback(this);
 
         getWindow().takeSurface(this);
         getWindow().takeInputQueue(this);
@@ -353,8 +347,8 @@
     }
     
     void preDispatchKeyEvent(KeyEvent event, int seq) {
-        mIMM.dispatchKeyEvent(this, seq, event,
-                mInputMethodCallback);
+        // FIXME: Input dispatch should be redirected back through ViewRootImpl again.
+        finishPreDispatchKeyEventNative(mNativeHandle, seq, false);
     }
 
     void setWindowFlags(int flags, int mask) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ebca041..a7543a8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1603,7 +1603,7 @@
             n.defaults = mDefaults;
             n.flags = mFlags;
             n.bigContentView = makeBigContentView();
-            if (mLedOnMs != 0 && mLedOffMs != 0) {
+            if (mLedOnMs != 0 || mLedOffMs != 0) {
                 n.flags |= FLAG_SHOW_LIGHTS;
             }
             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 5e69128..dbafc78 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -21,6 +21,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.StrictMode;
 import android.os.UserHandle;
 import android.util.Log;
 
@@ -126,6 +127,9 @@
         String pkg = mContext.getPackageName();
         if (notification.sound != null) {
             notification.sound = notification.sound.getCanonicalUri();
+            if (StrictMode.vmFileUriExposureEnabled()) {
+                notification.sound.checkFileUriExposed("Notification.sound");
+            }
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
         try {
@@ -148,6 +152,9 @@
         String pkg = mContext.getPackageName();
         if (notification.sound != null) {
             notification.sound = notification.sound.getCanonicalUri();
+            if (StrictMode.vmFileUriExposureEnabled()) {
+                notification.sound.checkFileUriExposed("Notification.sound");
+            }
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
         try {
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 37804e9..25c790f 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -260,7 +260,8 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
-            intent.setAllowFds(false);
+            intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -284,7 +285,8 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
-            intent.setAllowFds(false);
+            intent.migrateExtraStreamToClipData();
+            intent.prepareToLeaveProcess();
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -399,7 +401,8 @@
         String packageName = context.getPackageName();
         String[] resolvedTypes = new String[intents.length];
         for (int i=0; i<intents.length; i++) {
-            intents[i].setAllowFds(false);
+            intents[i].migrateExtraStreamToClipData();
+            intents[i].prepareToLeaveProcess();
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
         try {
@@ -424,7 +427,8 @@
         String packageName = context.getPackageName();
         String[] resolvedTypes = new String[intents.length];
         for (int i=0; i<intents.length; i++) {
-            intents[i].setAllowFds(false);
+            intents[i].migrateExtraStreamToClipData();
+            intents[i].prepareToLeaveProcess();
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
         try {
@@ -480,7 +484,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -524,7 +528,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
-            intent.setAllowFds(false);
+            intent.prepareToLeaveProcess();
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 02cf3aa..4fbca73 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -666,7 +666,9 @@
     
     /**
      * Print the Service's state into the given stream.  This gets invoked if
-     * you run "adb shell dumpsys activity service &lt;yourservicename&gt;".
+     * you run "adb shell dumpsys activity service &lt;yourservicename&gt;"
+     * (note that for this command to work, the service must be running, and
+     * you must specify a fully-qualified service name).
      * This is distinct from "dumpsys &lt;servicename&gt;", which only works for
      * named system services and which invokes the {@link IBinder#dump} method
      * on the {@link IBinder} interface registered with ServiceManager.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 9c0064e..3342068 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -709,7 +709,7 @@
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            WindowManagerGlobal.getWindowSession().setWallpaperPosition(
                     windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -747,7 +747,7 @@
             int x, int y, int z, Bundle extras) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+            WindowManagerGlobal.getWindowSession().sendWallpaperCommand(
                     windowToken, action, x, y, z, extras, false);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -767,7 +767,7 @@
      */
     public void clearWallpaperOffsets(IBinder windowToken) {
         try {
-            WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            WindowManagerGlobal.getWindowSession().setWallpaperPosition(
                     windowToken, -1, -1, -1, -1);
         } catch (RemoteException e) {
             // Ignore.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4c0eba0..8284b2c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1513,4 +1513,57 @@
             }
         }
     }
+
+    /**
+     * @hide
+     * Sets the given package as the device owner. The package must already be installed and there
+     * shouldn't be an existing device owner registered, for this call to succeed. Also, this
+     * method must be called before the device is provisioned.
+     * @param packageName the package name of the application to be registered as the device owner.
+     * @return whether the package was successfully registered as the device owner.
+     * @throws IllegalArgumentException if the package name is null or invalid
+     * @throws IllegalStateException if a device owner is already registered or the device has
+     *         already been provisioned.
+     */
+    public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
+            IllegalStateException {
+        if (mService != null) {
+            try {
+                return mService.setDeviceOwner(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to set device owner");
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Used to determine if a particular package has been registered as a Device Owner admin.
+     * Device Owner admins cannot be deactivated by the user unless the Device Owner itself allows
+     * it. And Device Owner packages cannot be uninstalled, once registered.
+     * @param packageName the package name to check against the registered device owner.
+     * @return whether or not the package is registered as the Device Owner.
+     */
+    public boolean isDeviceOwner(String packageName) {
+        if (mService != null) {
+            try {
+                return mService.isDeviceOwner(packageName);
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to check device owner");
+            }
+        }
+        return false;
+    }
+
+    /** @hide */
+    public String getDeviceOwner() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceOwner();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get device owner");
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e061ab3..b2a65bf 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -97,4 +97,8 @@
         int numbers, int symbols, int nonletter, int userHandle);
     void reportFailedPasswordAttempt(int userHandle);
     void reportSuccessfulPasswordAttempt(int userHandle);
+
+    boolean setDeviceOwner(String packageName);
+    boolean isDeviceOwner(String packageName);
+    String getDeviceOwner();
 }
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 44aa06f..37fddcb 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -472,25 +472,36 @@
                 File efLocation = getExternalFilesDir(null);
                 if (efLocation != null) {
                     basePath = getExternalFilesDir(null).getCanonicalPath();
+                    mode = -1;  // < 0 is a token to skip attempting a chmod()
                 }
             }
         } else {
             // Not a supported location
-            Log.i(TAG, "Data restored from non-app domain " + domain + ", ignoring");
+            Log.i(TAG, "Unrecognized domain " + domain);
         }
 
         // Now that we've figured out where the data goes, send it on its way
         if (basePath != null) {
+            // Canonicalize the nominal path and verify that it lies within the stated domain
             File outFile = new File(basePath, path);
-            if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outFile.getPath());
-            onRestoreFile(data, size, outFile, type, mode, mtime);
-        } else {
-            // Not a supported output location?  We need to consume the data
-            // anyway, so just use the default "copy the data out" implementation
-            // with a null destination.
-            if (DEBUG) Log.i(TAG, "[ skipping data from unsupported domain " + domain + "]");
-            FullBackup.restoreFile(data, size, type, mode, mtime, null);
+            String outPath = outFile.getCanonicalPath();
+            if (outPath.startsWith(basePath + File.separatorChar)) {
+                if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outPath);
+                onRestoreFile(data, size, outFile, type, mode, mtime);
+                return;
+            } else {
+                // Attempt to restore to a path outside the file's nominal domain.
+                if (DEBUG) {
+                    Log.e(TAG, "Cross-domain restore attempt: " + outPath);
+                }
+            }
         }
+
+        // Not a supported output location, or bad path:  we need to consume the data
+        // anyway, so just use the default "copy the data out" implementation
+        // with a null destination.
+        if (DEBUG) Log.i(TAG, "[ skipping file " + path + "]");
+        FullBackup.restoreFile(data, size, type, mode, mtime, null);
     }
 
     // ----- Core implementation -----
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 2fe08f3..cb0737e 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -89,7 +89,7 @@
      *    last modification time of the output file.  if the {@code mode} parameter is
      *    negative then this parameter will be ignored.
      * @param outFile Location within the filesystem to place the data.  This must point
-     *    to a location that is writeable by the caller, prefereably using an absolute path.
+     *    to a location that is writeable by the caller, preferably using an absolute path.
      * @throws IOException
      */
     static public void restoreFile(ParcelFileDescriptor data,
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index acdd0b5..bb4f5f1 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -152,6 +152,8 @@
      * @param fd The file descriptor to which a 'tar' file stream is to be written
      * @param includeApks If <code>true</code>, the resulting tar stream will include the
      *     application .apk files themselves as well as their data.
+     * @param includeObbs If <code>true</code>, the resulting tar stream will include any
+     *     application expansion (OBB) files themselves belonging to each application.
      * @param includeShared If <code>true</code>, the resulting tar stream will include
      *     the contents of the device's shared storage (SD card or equivalent).
      * @param allApps If <code>true</code>, the resulting tar stream will include all
@@ -164,8 +166,9 @@
      * @param packageNames The package names of the apps whose data (and optionally .apk files)
      *     are to be backed up.  The <code>allApps</code> parameter supersedes this.
      */
-    void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeShared,
-            boolean allApps, boolean allIncludesSystem, in String[] packageNames);
+    void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
+            boolean includeShared, boolean allApps, boolean allIncludesSystem,
+            in String[] packageNames);
 
     /**
      * Restore device content from the data stream passed through the given socket.  The
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index a470e70..c62bf32 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -338,8 +338,8 @@
      */
     public final AppWidgetHostView createView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
-        final int userId = context.getUserId();
-        AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
+        final int userId = mContext.getUserId();
+        AppWidgetHostView view = onCreateView(mContext, appWidgetId, appWidget);
         view.setUserId(userId);
         view.setOnClickHandler(mOnClickHandler);
         view.setAppWidget(appWidgetId, appWidget);
@@ -408,12 +408,10 @@
      * @hide
      */
     protected void onProvidersChanged(int userId) {
-        checkUserMatch(userId);
         // Does nothing
     }
 
     void updateAppWidgetView(int appWidgetId, RemoteViews views, int userId) {
-        checkUserMatch(userId);
         AppWidgetHostView v;
         synchronized (mViews) {
             v = mViews.get(appWidgetId);
@@ -424,7 +422,6 @@
     }
 
     void viewDataChanged(int appWidgetId, int viewId, int userId) {
-        checkUserMatch(userId);
         AppWidgetHostView v;
         synchronized (mViews) {
             v = mViews.get(appWidgetId);
@@ -434,16 +431,6 @@
         }
     }
 
-    // Ensure that the userId passed to us agrees with the one associated with this instance
-    // of AppWidgetHost.
-    // TODO: This should be removed in production code.
-    private void checkUserMatch(int userId) {
-        if (userId != mContext.getUserId()) {
-            throw new IllegalStateException(
-                "User ids don't match, userId=" + userId + ", mUserId=" + mContext.getUserId());
-        }
-    }
-
     /**
      * Clear the list of Views that have been created by this AppWidgetHost.
      */
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index e68d23a..1166e4b 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -49,8 +49,8 @@
     static final String TAG = "AppWidgetManager";
 
     /**
-     * Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
-     * The AppWidget picker activity will be launched.
+     * Activity action to launch from your {@link AppWidgetHost} activity when you want to
+     * pick an AppWidget to display.  The AppWidget picker activity will be launched.
      * <p>
      * You must supply the following extras:
      * <table>
@@ -89,8 +89,8 @@
             ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
 
     /**
-     * Send this from your {@link AppWidgetHost} activity when you want to bind an AppWidget to
-     * display and bindAppWidgetIdIfAllowed returns false.
+     * Activity action to launch from your {@link AppWidgetHost} activity when you want to bind
+     * an AppWidget to display and bindAppWidgetIdIfAllowed returns false.
      * <p>
      * You must supply the following extras:
      * <table>
@@ -269,6 +269,9 @@
     /**
      * Sent when the custom extras for an AppWidget change.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onAppWidgetOptionsChanged
      *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
      *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
@@ -278,6 +281,9 @@
     /**
      * Sent when an instance of an AppWidget is deleted from its host.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
      */
     public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
@@ -285,6 +291,9 @@
     /**
      * Sent when an instance of an AppWidget is removed from the last host.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
@@ -294,6 +303,9 @@
      * This broadcast is sent at boot time if there is a AppWidgetHost installed with
      * an instance for this provider.
      *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
      */
     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
old mode 100755
new mode 100644
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b00bf09..2e9c9e3 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -22,7 +22,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
@@ -359,6 +358,8 @@
     private IBluetooth mService;
 
     private Handler mServiceRecordHandler;
+    private BluetoothAdapterCallback mCallback;
+    private int mClientIf;
 
     /**
      * Get a handle to the default local Bluetooth adapter.
@@ -1137,7 +1138,8 @@
      * Get the profile proxy object associated with the profile.
      *
      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
-     * or {@link BluetoothProfile#A2DP}. Clients must implement
+     * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
+     * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
      * {@link BluetoothProfile.ServiceListener} to get notified of
      * the connection status and to get the proxy object.
      *
@@ -1166,12 +1168,6 @@
         } else if (profile == BluetoothProfile.HEALTH) {
             BluetoothHealth health = new BluetoothHealth(context, listener);
             return true;
-        } else if (profile == BluetoothProfile.GATT) {
-            BluetoothGatt gatt = new BluetoothGatt(context, listener);
-            return true;
-        } else if (profile == BluetoothProfile.GATT_SERVER) {
-            BluetoothGattServer gattServer = new BluetoothGattServer(context, listener);
-            return true;
         } else {
             return false;
         }
@@ -1411,4 +1407,230 @@
             mProxyServiceStateCallbacks.remove(cb);
         }
     }
+
+    /**
+     * Register an callback to receive async results, such as LE scan result.
+     *
+     * <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
+     */
+    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;
+        }
+    }
+
+    /**
+     * Starts a scan for Bluetooth LE devices.
+     *
+     * <p>Results of the scan are reported using the
+     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @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;
+    }
+
+    /**
+     * Starts a scan for Bluetooth LE devices, looking for devices that
+     * advertise given services.
+     *
+     * <p>Devices which advertise all specified services are reported using the
+     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param serviceUuids Array of services to look for
+     * @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;
+
+        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);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Stops an ongoing Bluetooth LE device scan.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     */
+    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);
+        }
+    }
+
+    /**
+     * 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);
+            }
+
+            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);
+
+                try {
+                    mCallback.onLeScan(getRemoteDevice(address), rssi, advData);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception: " + ex);
+                }
+            }
+
+            public void onGetService(String address, int srvcType,
+                                     int srvcInstId, ParcelUuid srvcUuid) {
+                // no op
+            }
+
+            public void onGetIncludedService(String address, int srvcType,
+                                             int srvcInstId, ParcelUuid srvcUuid,
+                                             int inclSrvcType, int inclSrvcInstId,
+                                             ParcelUuid inclSrvcUuid) {
+                // no op
+            }
+
+            public void onGetCharacteristic(String address, int srvcType,
+                             int srvcInstId, ParcelUuid srvcUuid,
+                             int charInstId, ParcelUuid charUuid,
+                             int charProps) {
+                // no op
+            }
+
+            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
+            }
+
+            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 onExecuteWrite(String address, 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
new file mode 100644
index 0000000..a726bc9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAdapterCallback.java
@@ -0,0 +1,57 @@
+/*
+ * 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/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
old mode 100755
new mode 100644
index 4cc22b4..3c1ec90
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -261,6 +262,26 @@
     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
 
     /**
+     * Bluetooth device type, Unknown
+     */
+    public static final int DEVICE_TYPE_UNKNOWN = 0;
+
+    /**
+     * Bluetooth device type, Classic - BR/EDR devices
+     */
+    public static final int DEVICE_TYPE_CLASSIC = 1;
+
+    /**
+     * Bluetooth device type, Low Energy - LE-only
+     */
+    public static final int DEVICE_TYPE_LE = 2;
+
+    /**
+     * Bluetooth device type, Dual Mode - BR/EDR/LE
+     */
+    public static final int DEVICE_TYPE_DUAL = 3;
+
+    /**
      * Broadcast Action: This intent is used to broadcast the {@link UUID}
      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
      * has been fetched. This intent is sent only when the UUIDs of the remote
@@ -601,6 +622,26 @@
     }
 
     /**
+     * Get the Bluetooth device type of the remote device.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
+     * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE}
+     *                         {@link #DEVICE_TYPE_DUAL}.
+     *         {@link #DEVICE_TYPE_UNKNOWN} if it's not available
+     */
+    public int getType() {
+        if (sService == null) {
+            Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
+            return DEVICE_TYPE_UNKNOWN;
+        }
+        try {
+            return sService.getRemoteType(this);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return DEVICE_TYPE_UNKNOWN;
+    }
+
+    /**
      * Get the Bluetooth alias of the remote device.
      * <p>Alias is the locally modified name of a remote device.
      *
@@ -1126,4 +1167,30 @@
         return pinBytes;
     }
 
+    /**
+     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as any further GATT client operations.
+     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+     * GATT client operations.
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param autoConnect Whether to directly connect to the remote device (false)
+     *                    or to automatically connect as soon as the remote
+     *                    device becomes available (true).
+     * @throws IllegalArgumentException if callback is null
+     */
+    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+                                     BluetoothGattCallback callback) {
+        // TODO(Bluetooth) check whether platform support BLE
+        //     Do the check here or in GattServer?
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        IBluetoothManager managerService = adapter.getBluetoothManager();
+        try {
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
+            BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this);
+            gatt.connect(autoConnect, callback);
+            return gatt;
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return null;
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 1e12025..bffe64b 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,8 +16,6 @@
 
 package android.bluetooth;
 
-
-import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothProfile.ServiceListener;
@@ -39,42 +37,49 @@
 import java.util.UUID;
 
 /**
- * Public API for the Bluetooth Gatt Profile.
+ * Public API for the Bluetooth GATT Profile.
  *
- * <p>This class provides Bluetooth Gatt functionality to enable communication
+ * <p>This class provides Bluetooth GATT functionality to enable communication
  * with Bluetooth Smart or Smart Ready devices.
  *
- * <p>BluetoothGatt is a proxy object for controlling the Bluetooth Service
- * via IPC.  Use {@link BluetoothAdapter#getProfileProxy} to get the
- * BluetoothGatt proxy object.
- *
  * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback}
- * and call {@link #registerApp} to register your application. Gatt capable
- * devices can be discovered using the {@link #startScan} function or the
- * regular Bluetooth device discovery process.
- * @hide
+ * and call {@link BluetoothDevice#connectGatt} to get a instance of this class.
+ * GATT capable devices can be discovered using the Bluetooth device discovery or BLE
+ * scan process.
  */
 public final class BluetoothGatt implements BluetoothProfile {
     private static final String TAG = "BluetoothGatt";
     private static final boolean DBG = true;
+    private static final boolean VDBG = true;
 
-    private Context mContext;
-    private ServiceListener mServiceListener;
-    private BluetoothAdapter mAdapter;
+    private final Context mContext;
     private IBluetoothGatt mService;
     private BluetoothGattCallback mCallback;
     private int mClientIf;
     private boolean mAuthRetry = false;
+    private BluetoothDevice mDevice;
+    private boolean mAutoConnect;
+    private int mConnState;
+    private final Object mStateLock = new Object();
+
+    private static final int CONN_STATE_IDLE = 0;
+    private static final int CONN_STATE_CONNECTING = 1;
+    private static final int CONN_STATE_CONNECTED = 2;
+    private static final int CONN_STATE_DISCONNECTING = 3;
+    private static final int CONN_STATE_CLOSED = 4;
 
     private List<BluetoothGattService> mServices;
 
-    /** A Gatt operation completed successfully */
+    /** A GATT operation failed */
+    public static final int GATT_FAILURE = 0;
+
+    /** A GATT operation completed successfully */
     public static final int GATT_SUCCESS = 0;
 
-    /** Gatt read operation is not permitted */
+    /** GATT read operation is not permitted */
     public static final int GATT_READ_NOT_PERMITTED = 0x2;
 
-    /** Gatt write operation is not permitted */
+    /** GATT write operation is not permitted */
     public static final int GATT_WRITE_NOT_PERMITTED = 0x3;
 
     /** Insufficient authentication for a given operation */
@@ -111,55 +116,6 @@
     /*package*/ static final int AUTHENTICATION_MITM = 2;
 
     /**
-     * Bluetooth state change handlers
-     */
-    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-        new IBluetoothStateChangeCallback.Stub() {
-            public void onBluetoothStateChange(boolean up) {
-                if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                if (!up) {
-                    if (DBG) Log.d(TAG,"Unbinding service...");
-                    synchronized (mConnection) {
-                        mService = null;
-                        mContext.unbindService(mConnection);
-                    }
-                } else {
-                    synchronized (mConnection) {
-                        if (mService == null) {
-                            if (DBG) Log.d(TAG,"Binding service...");
-                            if (!mContext.bindService(new Intent(IBluetoothGatt.class.getName()),
-                                                      mConnection, 0)) {
-                                Log.e(TAG, "Could not bind to Bluetooth GATT Service");
-                            }
-                        }
-                    }
-                }
-            }
-        };
-
-    /**
-     * Service binder handling
-     */
-    private ServiceConnection mConnection = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                if (DBG) Log.d(TAG, "Proxy object connected");
-                mService = IBluetoothGatt.Stub.asInterface(service);
-                ServiceListener serviceListener = mServiceListener;
-                if (serviceListener != null) {
-                    serviceListener.onServiceConnected(BluetoothProfile.GATT, BluetoothGatt.this);
-                }
-            }
-            public void onServiceDisconnected(ComponentName className) {
-                if (DBG) Log.d(TAG, "Proxy object disconnected");
-                mService = null;
-                ServiceListener serviceListener = mServiceListener;
-                if (serviceListener != null) {
-                    serviceListener.onServiceDisconnected(BluetoothProfile.GATT);
-                }
-            }
-        };
-
-    /**
      * Bluetooth GATT interface callbacks
      */
     private final IBluetoothGattCallback mBluetoothGattCallback =
@@ -171,11 +127,27 @@
             public void onClientRegistered(int status, int clientIf) {
                 if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
                     + " clientIf=" + clientIf);
+                if (VDBG) {
+                    synchronized(mStateLock) {
+                        if (mConnState != CONN_STATE_CONNECTING) {
+                            Log.e(TAG, "Bad connection state: " + mConnState);
+                        }
+                    }
+                }
                 mClientIf = clientIf;
+                if (status != GATT_SUCCESS) {
+                    mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
+                                                      BluetoothProfile.STATE_DISCONNECTED);
+                    synchronized(mStateLock) {
+                        mConnState = CONN_STATE_IDLE;
+                    }
+                    return;
+                }
                 try {
-                    mCallback.onAppRegistered(status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                    mService.clientConnect(mClientIf, mDevice.getAddress(),
+                                           !mAutoConnect); // autoConnect is inverse of "isDirect"
+                } catch (RemoteException e) {
+                    Log.e(TAG,"",e);
                 }
             }
 
@@ -187,13 +159,24 @@
                                                 boolean connected, String address) {
                 if (DBG) Log.d(TAG, "onClientConnectionState() - status=" + status
                                  + " clientIf=" + clientIf + " device=" + address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
+                                               BluetoothProfile.STATE_DISCONNECTED;
                 try {
-                    mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status,
-                                                      connected ? BluetoothProfile.STATE_CONNECTED
-                                                      : BluetoothProfile.STATE_DISCONNECTED);
+                    mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
+
+                synchronized(mStateLock) {
+                    if (connected) {
+                        mConnState = CONN_STATE_CONNECTED;
+                    } else {
+                        mConnState = CONN_STATE_IDLE;
+                    }
+                }
             }
 
             /**
@@ -201,13 +184,7 @@
              * @hide
              */
             public void onScanResult(String address, int rssi, byte[] advData) {
-                if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
-
-                try {
-                    mCallback.onScanResult(mAdapter.getRemoteDevice(address), rssi, advData);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
-                }
+                // no op
             }
 
             /**
@@ -219,8 +196,10 @@
             public void onGetService(String address, int srvcType,
                                      int srvcInstId, ParcelUuid srvcUuid) {
                 if (DBG) Log.d(TAG, "onGetService() - Device=" + address + " UUID=" + srvcUuid);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                mServices.add(new BluetoothGattService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                mServices.add(new BluetoothGattService(mDevice, srvcUuid.getUuid(),
                                                        srvcInstId, srvcType));
             }
 
@@ -236,10 +215,12 @@
                 if (DBG) Log.d(TAG, "onGetIncludedService() - Device=" + address
                     + " UUID=" + srvcUuid + " Included=" + inclSrvcUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device,
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice,
                         srvcUuid.getUuid(), srvcInstId, srvcType);
-                BluetoothGattService includedService = getService(device,
+                BluetoothGattService includedService = getService(mDevice,
                         inclSrvcUuid.getUuid(), inclSrvcInstId, inclSrvcType);
 
                 if (service != null && includedService != null) {
@@ -260,8 +241,10 @@
                 if (DBG) Log.d(TAG, "onGetCharacteristic() - Device=" + address + " UUID=" +
                                charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service != null) {
                     service.addCharacteristic(new BluetoothGattCharacteristic(
@@ -281,8 +264,10 @@
                              ParcelUuid descUuid) {
                 if (DBG) Log.d(TAG, "onGetDescriptor() - Device=" + address + " UUID=" + descUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -303,9 +288,11 @@
              */
             public void onSearchComplete(String address, int status) {
                 if (DBG) Log.d(TAG, "onSearchComplete() = Device=" + address + " Status=" + status);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 try {
-                    mCallback.onServicesDiscovered(device, status);
+                    mCallback.onServicesDiscovered(BluetoothGatt.this, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -322,6 +309,9 @@
                 if (DBG) Log.d(TAG, "onCharacteristicRead() - Device=" + address
                             + " UUID=" + charUuid + " Status=" + status);
 
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
                   || status == GATT_INSUFFICIENT_ENCRYPTION)
                   && mAuthRetry == false) {
@@ -338,8 +328,7 @@
 
                 mAuthRetry = false;
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -350,7 +339,7 @@
                 if (status == 0) characteristic.setValue(value);
 
                 try {
-                    mCallback.onCharacteristicRead(characteristic, status);
+                    mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -367,8 +356,10 @@
                 if (DBG) Log.d(TAG, "onCharacteristicWrite() - Device=" + address
                             + " UUID=" + charUuid + " Status=" + status);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -394,7 +385,7 @@
                 mAuthRetry = false;
 
                 try {
-                    mCallback.onCharacteristicWrite(characteristic, status);
+                    mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -411,8 +402,10 @@
                              byte[] value) {
                 if (DBG) Log.d(TAG, "onNotify() - Device=" + address + " UUID=" + charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -423,7 +416,7 @@
                 characteristic.setValue(value);
 
                 try {
-                    mCallback.onCharacteristicChanged(characteristic);
+                    mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -439,8 +432,10 @@
                              ParcelUuid descrUuid, byte[] value) {
                 if (DBG) Log.d(TAG, "onDescriptorRead() - Device=" + address + " UUID=" + charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -470,7 +465,7 @@
                 mAuthRetry = true;
 
                 try {
-                    mCallback.onDescriptorRead(descriptor, status);
+                    mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -486,8 +481,10 @@
                              ParcelUuid descrUuid) {
                 if (DBG) Log.d(TAG, "onDescriptorWrite() - Device=" + address + " UUID=" + charUuid);
 
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                BluetoothGattService service = getService(device, srvcUuid.getUuid(),
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
 
@@ -516,7 +513,7 @@
                 mAuthRetry = false;
 
                 try {
-                    mCallback.onDescriptorWrite(descriptor, status);
+                    mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -529,9 +526,11 @@
             public void onExecuteWrite(String address, int status) {
                 if (DBG) Log.d(TAG, "onExecuteWrite() - Device=" + address
                     + " status=" + status);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 try {
-                    mCallback.onReliableWriteCompleted(device, status);
+                    mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
@@ -544,70 +543,34 @@
             public void onReadRemoteRssi(String address, int rssi, int status) {
                 if (DBG) Log.d(TAG, "onReadRemoteRssi() - Device=" + address +
                             " rssi=" + rssi + " status=" + status);
-                BluetoothDevice device = mAdapter.getRemoteDevice(address);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
                 try {
-                    mCallback.onReadRemoteRssi(device, rssi, status);
+                    mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
                 } catch (Exception ex) {
                     Log.w(TAG, "Unhandled exception: " + ex);
                 }
             }
         };
 
-    /**
-     * Create a BluetoothGatt proxy object.
-     */
-    /*package*/ BluetoothGatt(Context context, ServiceListener l) {
+    /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device) {
         mContext = context;
-        mServiceListener = l;
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mService = iGatt;
+        mDevice = device;
         mServices = new ArrayList<BluetoothGattService>();
 
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
-            try {
-                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re);
-            }
-        } else {
-            Log.e(TAG, "Unable to get BluetoothManager interface.");
-            throw new RuntimeException("BluetoothManager inactive");
-        }
-
-        //Bind to the service only if the Bluetooth is ON
-        if(mAdapter.isEnabled()){
-            if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) {
-                Log.e(TAG, "Could not bind to Bluetooth Gatt Service");
-            }
-        }
+        mConnState = CONN_STATE_IDLE;
     }
 
     /**
-     * Close the connection to the gatt service.
+     * Close this Bluetooth GATT client.
      */
-    /*package*/ void close() {
+    public void close() {
         if (DBG) Log.d(TAG, "close()");
 
         unregisterApp();
-        mServiceListener = null;
-
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
-            try {
-                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re);
-            }
-        }
-
-        synchronized (mConnection) {
-            if (mService != null) {
-                mService = null;
-                mContext.unbindService(mConnection);
-            }
-        }
+        mConnState = CONN_STATE_CLOSED;
     }
 
     /**
@@ -629,18 +592,18 @@
 
 
     /**
-     * Register an application callback to start using Gatt.
+     * Register an application callback to start using GATT.
      *
-     * <p>This is an asynchronous call. The callback is used to notify
-     * success or failure if the function returns true.
+     * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
+     * is used to notify success or failure if the function returns true.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param callback Gatt callback handler that will receive asynchronous
-     *          callbacks.
-     * @return true, if application was successfully registered.
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @return If true, the callback will be called to notify success or failure,
+     *         false on immediate error
      */
-    public boolean registerApp(BluetoothGattCallback callback) {
+    private boolean registerApp(BluetoothGattCallback callback) {
         if (DBG) Log.d(TAG, "registerApp()");
         if (mService == null) return false;
 
@@ -661,7 +624,7 @@
     /**
      * Unregister the current application and callbacks.
      */
-    public void unregisterApp() {
+    private void unregisterApp() {
         if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
         if (mService == null || mClientIf == 0) return;
 
@@ -675,77 +638,7 @@
     }
 
     /**
-     * Starts a scan for Bluetooth LE devices.
-     *
-     * <p>Results of the scan are reported using the
-     * {@link BluetoothGattCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan() {
-        if (DBG) Log.d(TAG, "startScan()");
-        if (mService == null || mClientIf == 0) return false;
-
-        try {
-            mService.startScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Starts a scan for Bluetooth LE devices, looking for devices that
-     * advertise given services.
-     *
-     * <p>Devices which advertise all specified services are reported using the
-     * {@link BluetoothGattCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param serviceUuids Array of services to look for
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan(UUID[] serviceUuids) {
-        if (DBG) Log.d(TAG, "startScan() - with UUIDs");
-        if (mService == null || mClientIf == 0) return false;
-
-        try {
-            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
-            for(int i = 0; i != uuids.length; ++i) {
-                uuids[i] = new ParcelUuid(serviceUuids[i]);
-            }
-            mService.startScanWithUuids(mClientIf, false, uuids);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Stops an ongoing Bluetooth LE device scan.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     */
-    public void stopScan() {
-        if (DBG) Log.d(TAG, "stopScan()");
-        if (mService == null || mClientIf == 0) return;
-
-        try {
-            mService.stopScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-    }
-
-    /**
-     * Initiate a connection to a Bluetooth Gatt capable device.
+     * Initiate a connection to a Bluetooth GATT capable device.
      *
      * <p>The connection may not be established right away, but will be
      * completed when the remote device is available. A
@@ -757,7 +650,7 @@
      * when the remote device is in range/available. Generally, the first ever
      * connection to a device should be direct (autoConnect set to false) and
      * subsequent connections to known devices should be invoked with the
-     * autoConnect parameter set to false.
+     * autoConnect parameter set to true.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
@@ -767,18 +660,24 @@
      *                    device becomes available (true).
      * @return true, if the connection attempt was initiated successfully
      */
-    public boolean connect(BluetoothDevice device, boolean autoConnect) {
-        if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
-        if (mService == null || mClientIf == 0) return false;
-
-        try {
-            mService.clientConnect(mClientIf, device.getAddress(),
-                                   autoConnect ? false : true); // autoConnect is inverse of "isDirect"
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
+    /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
+        if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
+        synchronized(mStateLock) {
+            if (mConnState != CONN_STATE_IDLE) {
+                throw new IllegalStateException("Not idle");
+            }
+            mConnState = CONN_STATE_CONNECTING;
+        }
+        if (!registerApp(callback)) {
+            synchronized(mStateLock) {
+                mConnState = CONN_STATE_IDLE;
+            }
+            Log.e(TAG, "Failed to register callback");
             return false;
         }
 
+        // the connection will continue after successful callback registration
+        mAutoConnect = autoConnect;
         return true;
     }
 
@@ -787,21 +686,48 @@
      * currently in progress.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote device
      */
-    public void cancelConnection(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "cancelOpen() - device: " + device.getAddress());
+    public void disconnect() {
+        if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return;
 
         try {
-            mService.clientDisconnect(mClientIf, device.getAddress());
+            mService.clientDisconnect(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
         }
     }
 
     /**
+     * Connect back to remote device.
+     *
+     * <p>This method is used to re-connect to a remote device after the
+     * connection has been dropped. If the device is not in range, the
+     * re-connection will be triggered once the device is back in range.
+     *
+     * @return true, if the connection attempt was initiated successfully
+     */
+    public boolean connect() {
+        try {
+            mService.clientConnect(mClientIf, mDevice.getAddress(),
+                                   false); // autoConnect is inverse of "isDirect"
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+    }
+
+    /**
+     * Return the remote bluetooth device this GATT client targets to
+     *
+     * @return remote bluetooth device
+     */
+    public BluetoothDevice getDevice() {
+        return mDevice;
+    }
+
+    /**
      * Discovers services offered by a remote device as well as their
      * characteristics and descriptors.
      *
@@ -812,17 +738,16 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device to explore
      * @return true, if the remote service discovery has been started
      */
-    public boolean discoverServices(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "discoverServices() - device: " + device.getAddress());
+    public boolean discoverServices() {
+        if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         mServices.clear();
 
         try {
-            mService.discoverServices(mClientIf, device.getAddress());
+            mService.discoverServices(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -839,16 +764,15 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return List of services on the remote device. Returns an empty list
      *         if service discovery has not yet been performed.
      */
-    public List<BluetoothGattService> getServices(BluetoothDevice device) {
+    public List<BluetoothGattService> getServices() {
         List<BluetoothGattService> result =
                 new ArrayList<BluetoothGattService>();
 
         for (BluetoothGattService service : mServices) {
-            if (service.getDevice().equals(device)) {
+            if (service.getDevice().equals(mDevice)) {
                 result.add(service);
             }
         }
@@ -868,14 +792,13 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @param uuid UUID of the requested service
      * @return BluetoothGattService if supported, or null if the requested
      *         service is not offered by the remote device.
      */
-    public BluetoothGattService getService(BluetoothDevice device, UUID uuid) {
+    public BluetoothGattService getService(UUID uuid) {
         for (BluetoothGattService service : mServices) {
-            if (service.getDevice().equals(device) &&
+            if (service.getDevice().equals(mDevice) &&
                 service.getUuid().equals(uuid)) {
                 return service;
             }
@@ -923,8 +846,7 @@
     }
 
     /**
-     * Writes a given characteristic and it's values to the associated remote
-     * device.
+     * Writes a given characteristic and its values to the associated remote device.
      *
      * <p>Once the write operation has been completed, the
      * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
@@ -1061,15 +983,14 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return true, if the reliable write transaction has been initiated
      */
-    public boolean beginReliableWrite(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + device.getAddress());
+    public boolean beginReliableWrite() {
+        if (DBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.beginReliableWrite(mClientIf, device.getAddress());
+            mService.beginReliableWrite(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1089,15 +1010,14 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return true, if the request to execute the transaction has been sent
      */
-    public boolean executeReliableWrite(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + device.getAddress());
+    public boolean executeReliableWrite() {
+        if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.endReliableWrite(mClientIf, device.getAddress(), true);
+            mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1113,15 +1033,13 @@
      * operations for a given remote device.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote device
      */
-    public void abortReliableWrite(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + device.getAddress());
+    public void abortReliableWrite(BluetoothDevice mDevice) {
+        if (DBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return;
 
         try {
-            mService.endReliableWrite(mClientIf, device.getAddress(), false);
+            mService.endReliableWrite(mClientIf, mDevice.getAddress(), false);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
         }
@@ -1172,12 +1090,12 @@
      * remote device.
      * @hide
      */
-    public boolean refresh(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "refresh() - device: " + device.getAddress());
+    public boolean refresh() {
+        if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.refreshDevice(mClientIf, device.getAddress());
+            mService.refreshDevice(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1194,15 +1112,14 @@
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device
      * @return true, if the RSSI value has been requested successfully
      */
-    public boolean readRemoteRssi(BluetoothDevice device) {
-        if (DBG) Log.d(TAG, "readRssi() - device: " + device.getAddress());
+    public boolean readRemoteRssi() {
+        if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
         try {
-            mService.readRemoteRssi(mClientIf, device.getAddress());
+            mService.readRemoteRssi(mClientIf, mDevice.getAddress());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
             return false;
@@ -1212,98 +1129,38 @@
     }
 
     /**
-     * Get the current connection state of the profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote bluetooth device.
-     * @return State of the profile connection. One of
-     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
+     * @throws UnsupportedOperationException
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        if (DBG) Log.d(TAG,"getConnectionState()");
-        if (mService == null) return STATE_DISCONNECTED;
-
-        List<BluetoothDevice> connectedDevices = getConnectedDevices();
-        for(BluetoothDevice connectedDevice : connectedDevices) {
-            if (device.equals(connectedDevice)) {
-                return STATE_CONNECTED;
-            }
-        }
-
-        return STATE_DISCONNECTED;
+        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
     }
 
     /**
-     * Get connected devices for the Gatt profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        if (DBG) Log.d(TAG,"getConnectedDevices");
-
-        List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return connectedDevices;
-
-        try {
-            connectedDevices = mService.getDevicesMatchingConnectionStates(
-                new int[] { BluetoothProfile.STATE_CONNECTED });
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return connectedDevices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getConnectedDevices instead.");
     }
 
     /**
-     * Get a list of devices that match any of the given connection
-     * states.
+     * Not supported - please use
+     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
+     * with {@link BluetoothProfile#GATT} as first argument
      *
-     * <p> If none of the devices match any of the given states,
-     * an empty list will be returned.
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param states Array of states. States can be one of
-     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
-
-        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return devices;
-
-        try {
-            devices = mService.getDevicesMatchingConnectionStates(states);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return devices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index afa4539..2259c1e 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -16,70 +16,46 @@
 
 package android.bluetooth;
 
-import android.bluetooth.BluetoothDevice;
-
-import android.util.Log;
-
 /**
  * This abstract class is used to implement {@link BluetoothGatt} callbacks.
- * @hide
  */
 public abstract class BluetoothGattCallback {
-    /**
-     * Callback to inform change in registration state of the  application.
-     *
-     * @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the application
-     *               was successfully registered.
-     */
-    public void onAppRegistered(int status) {
-    }
 
     /**
-     * Callback reporting an LE device found during a device scan initiated
-     * by the {@link BluetoothGatt#startScan} function.
+     * Callback indicating when GATT client has connected/disconnected to/from a remote
+     * GATT server.
      *
-     * @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 onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
-    }
-
-    /**
-     * Callback indicating when a remote device has been connected or disconnected.
-     *
-     * @param device Remote device that has been connected or disconnected.
+     * @param gatt GATT client
      * @param status Status of the connect or disconnect operation.
      * @param newState Returns the new connection state. Can be one of
      *                  {@link BluetoothProfile#STATE_DISCONNECTED} or
      *                  {@link BluetoothProfile#STATE_CONNECTED}
      */
-    public void onConnectionStateChange(BluetoothDevice device, int status,
+    public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                         int newState) {
     }
 
     /**
-     * Callback invoked when the list of remote services, characteristics and
-     * descriptors for the remote device have been updated.
+     * Callback invoked when the list of remote services, characteristics and descriptors
+     * for the remote device have been updated, ie new services have been discovered.
      *
-     * @param device Remote device
+     * @param gatt GATT client invoked {@link BluetoothGatt#discoverServices}
      * @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device
      *               has been explored successfully.
      */
-    public void onServicesDiscovered(BluetoothDevice device, int status) {
+    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
     }
 
     /**
      * Callback reporting the result of a characteristic read operation.
      *
+     * @param gatt GATT client invoked {@link BluetoothGatt#readCharacteristic}
      * @param characteristic Characteristic that was read from the associated
      *                       remote device.
      * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation
      *               was completed successfully.
      */
-    public void onCharacteristicRead(BluetoothGattCharacteristic characteristic,
+    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
                                      int status) {
     }
 
@@ -92,54 +68,59 @@
      * value to the desired value to be written. If the values don't match,
      * the application must abort the reliable write transaction.
      *
+     * @param gatt GATT client invoked {@link BluetoothGatt#writeCharacteristic}
      * @param characteristic Characteristic that was written to the associated
      *                       remote device.
      * @param status The result of the write operation
      */
-    public void onCharacteristicWrite(BluetoothGattCharacteristic characteristic,
-                               int status) {
+    public void onCharacteristicWrite(BluetoothGatt gatt,
+                                      BluetoothGattCharacteristic characteristic, int status) {
     }
 
     /**
      * Callback triggered as a result of a remote characteristic notification.
      *
+     * @param gatt GATT client the characteristic is associated with
      * @param characteristic Characteristic that has been updated as a result
      *                       of a remote notification event.
      */
-    public void onCharacteristicChanged(BluetoothGattCharacteristic characteristic) {
+    public void onCharacteristicChanged(BluetoothGatt gatt,
+                                        BluetoothGattCharacteristic characteristic) {
     }
 
     /**
      * Callback reporting the result of a descriptor read operation.
      *
+     * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
      * @param descriptor Descriptor that was read from the associated
-     *                       remote device.
+     *                   remote device.
      * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation
      *               was completed successfully
      */
-    public void onDescriptorRead(BluetoothGattDescriptor descriptor,
-                                     int status) {
+    public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+                                 int status) {
     }
 
     /**
      * Callback indicating the result of a descriptor write operation.
      *
+     * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor}
      * @param descriptor Descriptor that was writte to the associated
-     *                       remote device.
+     *                   remote device.
      * @param status The result of the write operation
      */
-    public void onDescriptorWrite(BluetoothGattDescriptor descriptor,
-                               int status) {
+    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+                                  int status) {
     }
 
     /**
      * Callback invoked when a reliable write transaction has been completed.
      *
-     * @param device Remote device
+     * @param gatt GATT client invoked {@link BluetoothGatt#executeReliableWrite}
      * @param status {@link BluetoothGatt#GATT_SUCCESS} if the reliable write
      *               transaction was executed successfully
      */
-    public void onReliableWriteCompleted(BluetoothDevice device, int status) {
+    public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
     }
 
     /**
@@ -148,10 +129,10 @@
      * This callback is triggered in response to the
      * {@link BluetoothGatt#readRemoteRssi} function.
      *
-     * @param device Identifies the remote device
+     * @param gatt GATT client invoked {@link BluetoothGatt#readRemoteRssi}
      * @param rssi The RSSI value for the remote device
-     * @param status 0 if the RSSI was read successfully
+     * @param status {@link BluetoothGatt#GATT_SUCCESS} if the RSSI was read successfully
      */
-    public void onReadRemoteRssi(BluetoothDevice device, int rssi, int status) {
+    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
index 18492ab..033f079 100644
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
@@ -21,8 +21,11 @@
 import java.util.UUID;
 
 /**
- * Represents a Bluetooth Gatt Characteristic
- * @hide
+ * Represents a Bluetooth GATT Characteristic
+ *
+ * <p>A GATT characteristic is a basic data element used to construct a GATT service,
+ * {@link BluetoothGattService}. The characteristic contains a value as well as
+ * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}.
  */
 public class BluetoothGattCharacteristic {
 
@@ -119,7 +122,7 @@
     public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
 
     /**
-     * Write characteristic including and authenticated signature
+     * Write characteristic including authentication signature
      */
     public static final int WRITE_TYPE_SIGNED = 0x04;
 
@@ -219,12 +222,30 @@
     protected List<BluetoothGattDescriptor> mDescriptors;
 
     /**
+     * Create a new BluetoothGattCharacteristic.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param uuid The UUID for this characteristic
+     * @param properties Properties of this characteristic
+     * @param permissions Permissions for this characteristic
+     */
+    public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
+        initCharacteristic(null, uuid, 0, properties, permissions);
+    }
+
+    /**
      * Create a new BluetoothGattCharacteristic
      * @hide
      */
     /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
                                             UUID uuid, int instanceId,
                                             int properties, int permissions) {
+        initCharacteristic(service, uuid, instanceId, properties, permissions);
+    }
+
+    private void initCharacteristic(BluetoothGattService service,
+                                    UUID uuid, int instanceId,
+                                    int properties, int permissions) {
         mUuid = uuid;
         mInstance = instanceId;
         mProperties = properties;
@@ -249,11 +270,16 @@
     }
 
     /**
-     * Add a descriptor to this characteristic
-     * @hide
+     * Adds a descriptor to this characteristic.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param descriptor Descriptor to be added to this characteristic.
+     * @return true, if the descriptor was added to the characteristic
      */
-    /*package*/ void addDescriptor(BluetoothGattDescriptor descriptor) {
+    public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
         mDescriptors.add(descriptor);
+        descriptor.setCharacteristic(this);
+        return true;
     }
 
     /**
@@ -265,8 +291,15 @@
     }
 
     /**
+     * Sets the service associated with this device.
+     * @hide
+     */
+    /*package*/ void setService(BluetoothGattService service) {
+        mService = service;
+    }
+
+    /**
      * Returns the UUID of this characteristic
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return UUID of this characteristic
      */
@@ -280,8 +313,6 @@
      * <p>If a remote device offers multiple characteristics with the same UUID,
      * the instance ID is used to distuinguish between characteristics.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Instance ID of this characteristic
      */
     public int getInstanceId() {
@@ -294,8 +325,6 @@
      * <p>The properties contain a bit mask of property flags indicating
      * the features of this characteristic.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Properties of this characteristic
      */
     public int getProperties() {
@@ -304,7 +333,6 @@
 
     /**
      * Returns the permissions for this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Permissions of this characteristic
      */
@@ -314,7 +342,6 @@
 
     /**
      * Gets the write type for this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Write type for this characteristic
      */
@@ -329,11 +356,6 @@
      * {@link BluetoothGatt#writeCharacteristic} function write this
      * characteristic.
      *
-     * <p>The default write type for a characteristic is
-     * {@link #WRITE_TYPE_DEFAULT}.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param writeType The write type to for this characteristic. Can be one
      *                  of:
      *                  {@link #WRITE_TYPE_DEFAULT},
@@ -345,8 +367,15 @@
     }
 
     /**
+     * Set the desired key size.
+     * @hide
+     */
+    public void setKeySize(int keySize) {
+        mKeySize = keySize;
+    }
+
+    /**
      * Returns a list of descriptors for this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Descriptors for this characteristic
      */
@@ -358,9 +387,7 @@
      * Returns a descriptor with a given UUID out of the list of
      * descriptors for this characteristic.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return Gatt descriptor object or null if no descriptor with the
+     * @return GATT descriptor object or null if no descriptor with the
      *         given UUID was found.
      */
     public BluetoothGattDescriptor getDescriptor(UUID uuid) {
@@ -376,12 +403,10 @@
      * Get the stored value for this characteristic.
      *
      * <p>This function returns the stored value for this characteristic as
-     * retrieved by calling {@link BluetoothGatt#readCharacteristic}. To cached
+     * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
      * value of the characteristic is updated as a result of a read characteristic
      * operation or if a characteristic update notification has been received.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Cached value of the characteristic
      */
     public byte[] getValue() {
@@ -397,8 +422,6 @@
      * characteristic value at the given offset are interpreted to generate the
      * return value.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param formatType The format type used to interpret the characteristic
      *                   value.
      * @param offset Offset at which the integer value can be found.
@@ -436,7 +459,6 @@
     /**
      * Return the stored value of this characteristic.
      * <p>See {@link #getValue} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param formatType The format type used to interpret the characteristic
      *                   value.
@@ -462,7 +484,7 @@
     /**
      * Return the stored value of this characteristic.
      * <p>See {@link #getValue} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param offset Offset at which the string value can be found.
      * @return Cached value of the characteristic
      */
@@ -481,8 +503,6 @@
      * {@link BluetoothGatt#writeCharacteristic} to send the value to the
      * remote device.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param value New value for this characteristic
      * @return true if the locally stored value has been set, false if the
      *              requested value could not be stored locally.
@@ -495,7 +515,6 @@
     /**
      * Set the locally stored value of this characteristic.
      * <p>See {@link #setValue(byte[])} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param value New value for this characteristic
      * @param formatType Integer format type used to transform the value parameter
@@ -529,7 +548,8 @@
             case FORMAT_UINT32:
                 mValue[offset++] = (byte)(value & 0xFF);
                 mValue[offset++] = (byte)((value >> 8) & 0xFF);
-                mValue[offset] = (byte)((value >> 16) & 0xFF);
+                mValue[offset++] = (byte)((value >> 16) & 0xFF);
+                mValue[offset] = (byte)((value >> 24) & 0xFF);
                 break;
 
             default:
@@ -541,7 +561,7 @@
     /**
      * Set the locally stored value of this characteristic.
      * <p>See {@link #setValue(byte[])} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param mantissa Mantissa for this characteristic
      * @param exponent  exponent value for this characteristic
      * @param formatType Float format type used to transform the value parameter
@@ -581,7 +601,7 @@
     /**
      * Set the locally stored value of this characteristic.
      * <p>See {@link #setValue(byte[])} for details.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param value New value for this characteristic
      * @return true if the locally stored value has been set
      */
@@ -592,7 +612,6 @@
 
     /**
      * Returns the size of a give value type.
-     * @hide
      */
     private int getTypeLen(int formatType) {
         return formatType & 0xF;
@@ -600,7 +619,6 @@
 
     /**
      * Convert a signed byte to an unsigned int.
-     * @hide
      */
     private int unsignedByteToInt(byte b) {
         return b & 0xFF;
@@ -608,7 +626,6 @@
 
     /**
      * Convert signed bytes to a 16-bit unsigned int.
-     * @hide
      */
     private int unsignedBytesToInt(byte b0, byte b1) {
         return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
@@ -616,7 +633,6 @@
 
     /**
      * Convert signed bytes to a 32-bit unsigned int.
-     * @hide
      */
     private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
         return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
@@ -625,7 +641,6 @@
 
     /**
      * Convert signed bytes to a 16-bit short float value.
-     * @hide
      */
     private float bytesToFloat(byte b0, byte b1) {
         int mantissa = unsignedToSigned(unsignedByteToInt(b0)
@@ -636,7 +651,6 @@
 
     /**
      * Convert signed bytes to a 32-bit short float value.
-     * @hide
      */
     private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
         int mantissa = unsignedToSigned(unsignedByteToInt(b0)
@@ -648,7 +662,6 @@
     /**
      * Convert an unsigned integer value to a two's-complement encoded
      * signed value.
-     * @hide
      */
     private int unsignedToSigned(int unsigned, int size) {
         if ((unsigned & (1 << size-1)) != 0) {
@@ -659,7 +672,6 @@
 
     /**
      * Convert an integer into the signed bits of a given length.
-     * @hide
      */
     private int intToSignedBits(int i, int size) {
         if (i < 0) {
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
index ba1f28a..1cd6878 100644
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ b/core/java/android/bluetooth/BluetoothGattDescriptor.java
@@ -19,8 +19,11 @@
 import java.util.UUID;
 
 /**
- * Represents a Bluetooth Gatt Descriptor
- * @hide
+ * Represents a Bluetooth GATT Descriptor
+ *
+ * <p> GATT Descriptors contain additional information and attributes of a GATT
+ * characteristic, {@link BluetoothGattCharacteristic}. They can be used to describe
+ * the characteristic's features or to control certain behaviours of the characteristic.
  */
 public class BluetoothGattDescriptor {
 
@@ -109,12 +112,28 @@
      * Create a new BluetoothGattDescriptor.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
+     * @param uuid The UUID for this descriptor
+     * @param permissions Permissions for this descriptor
+     */
+    public BluetoothGattDescriptor(UUID uuid, int permissions) {
+        initDescriptor(null, uuid, permissions);
+    }
+
+    /**
+     * Create a new BluetoothGattDescriptor.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
      * @param characteristic The characteristic this descriptor belongs to
      * @param uuid The UUID for this descriptor
      * @param permissions Permissions for this descriptor
      */
     /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
                                     int permissions) {
+        initDescriptor(characteristic, uuid, permissions);
+    }
+
+    private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
+                                int permissions) {
         mCharacteristic = characteristic;
         mUuid = uuid;
         mPermissions = permissions;
@@ -129,8 +148,15 @@
     }
 
     /**
+     * Set the back-reference to the associated characteristic
+     * @hide
+     */
+    /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
+        mCharacteristic = characteristic;
+    }
+
+    /**
      * Returns the UUID of this descriptor.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return UUID of this descriptor
      */
@@ -140,7 +166,6 @@
 
     /**
      * Returns the permissions for this descriptor.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Permissions of this descriptor
      */
@@ -152,12 +177,10 @@
      * Returns the stored value for this descriptor
      *
      * <p>This function returns the stored value for this descriptor as
-     * retrieved by calling {@link BluetoothGatt#readDescriptor}. To cached
+     * retrieved by calling {@link BluetoothGatt#readDescriptor}. The cached
      * value of the descriptor is updated as a result of a descriptor read
      * operation.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Cached value of the descriptor
      */
     public byte[] getValue() {
@@ -172,8 +195,6 @@
      * {@link BluetoothGatt#writeDescriptor} to send the value to the
      * remote device.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @param value New value for this descriptor
      * @return true if the locally stored value has been set, false if the
      *              requested value could not be stored locally.
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 91a1a94..644c619b 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -38,88 +38,30 @@
 import java.util.UUID;
 
 /**
- * Public API for the Bluetooth Gatt Profile server role.
+ * Public API for the Bluetooth GATT Profile server role.
  *
- * <p>This class provides Bluetooth Gatt server role functionality,
+ * <p>This class provides Bluetooth GATT server role functionality,
  * allowing applications to create and advertise Bluetooth Smart services
  * and characteristics.
  *
  * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
  * via IPC.  Use {@link BluetoothAdapter#getProfileProxy} to get the
  * BluetoothGatt proxy object.
- * @hide
  */
 public final class BluetoothGattServer implements BluetoothProfile {
     private static final String TAG = "BluetoothGattServer";
     private static final boolean DBG = true;
 
-    private Context mContext;
-    private ServiceListener mServiceListener;
+    private final Context mContext;
     private BluetoothAdapter mAdapter;
     private IBluetoothGatt mService;
     private BluetoothGattServerCallback mCallback;
-    private int mServerIf;
 
+    private Object mServerIfLock = new Object();
+    private int mServerIf;
     private List<BluetoothGattService> mServices;
 
-    /**
-     * Bluetooth state change handlers
-     */
-    private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
-        new IBluetoothStateChangeCallback.Stub() {
-            public void onBluetoothStateChange(boolean up) {
-                if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
-                if (!up) {
-                    if (DBG) Log.d(TAG,"Unbinding service...");
-                    synchronized (mConnection) {
-                        try {
-                            mService = null;
-                            mContext.unbindService(mConnection);
-                        } catch (Exception re) {
-                            Log.e(TAG,"",re);
-                        }
-                    }
-                } else {
-                    synchronized (mConnection) {
-                        try {
-                            if (mService == null) {
-                                if (DBG) Log.d(TAG,"Binding service...");
-                                if (!mContext.bindService(new
-                                        Intent(IBluetoothGatt.class.getName()),
-                                        mConnection, 0)) {
-                                    Log.e(TAG, "Could not bind to Bluetooth GATT Service");
-                                }
-                            }
-                        } catch (Exception re) {
-                            Log.e(TAG,"",re);
-                        }
-                    }
-                }
-            }
-        };
-
-    /**
-     * Service binder handling
-     */
-    private ServiceConnection mConnection = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                if (DBG) Log.d(TAG, "Proxy object connected");
-                mService = IBluetoothGatt.Stub.asInterface(service);
-                ServiceListener serviceListner = mServiceListener;
-                if (serviceListner != null) {
-                    serviceListner.onServiceConnected(BluetoothProfile.GATT_SERVER,
-                                                      BluetoothGattServer.this);
-                }
-            }
-            public void onServiceDisconnected(ComponentName className) {
-                if (DBG) Log.d(TAG, "Proxy object disconnected");
-                mService = null;
-                ServiceListener serviceListner = mServiceListener;
-                if (serviceListner != null) {
-                    serviceListner.onServiceDisconnected(BluetoothProfile.GATT_SERVER);
-                }
-            }
-        };
+    private static final int CALLBACK_REG_TIMEOUT = 10000;
 
     /**
      * Bluetooth GATT interface callbacks
@@ -133,11 +75,14 @@
             public void onServerRegistered(int status, int serverIf) {
                 if (DBG) Log.d(TAG, "onServerRegistered() - status=" + status
                     + " serverIf=" + serverIf);
-                mServerIf = serverIf;
-                try {
-                    mCallback.onAppRegistered(status);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+                synchronized(mServerIfLock) {
+                    if (mCallback != null) {
+                        mServerIf = serverIf;
+                        mServerIfLock.notify();
+                    } else {
+                        // registration timeout
+                        Log.e(TAG, "onServerRegistered: mCallback is null");
+                    }
                 }
             }
 
@@ -147,13 +92,7 @@
              */
             public void onScanResult(String address, int rssi, byte[] advData) {
                 if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
-
-                try {
-                    mCallback.onScanResult(mAdapter.getRemoteDevice(address),
-                                           rssi, advData);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
-                }
+                // no op
             }
 
             /**
@@ -209,8 +148,7 @@
                 BluetoothGattService service = getService(srvcUuid, srvcInstId, srvcType);
                 if (service == null) return;
 
-                BluetoothGattCharacteristic characteristic = service.getCharacteristic(
-                    charUuid);
+                BluetoothGattCharacteristic characteristic = service.getCharacteristic(charUuid);
                 if (characteristic == null) return;
 
                 try {
@@ -340,31 +278,13 @@
     /**
      * Create a BluetoothGattServer proxy object.
      */
-    /*package*/ BluetoothGattServer(Context context, ServiceListener l) {
+    /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt) {
         mContext = context;
-        mServiceListener = l;
+        mService = iGatt;
         mAdapter = BluetoothAdapter.getDefaultAdapter();
+        mCallback = null;
+        mServerIf = 0;
         mServices = new ArrayList<BluetoothGattService>();
-
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
-            try {
-                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to register BluetoothStateChangeCallback", re);
-            }
-        } else {
-            Log.e(TAG, "Unable to get BluetoothManager interface.");
-            throw new RuntimeException("BluetoothManager inactive");
-        }
-
-        //Bind to the service only if the Bluetooth is ON
-        if(mAdapter.isEnabled()){
-            if (!context.bindService(new Intent(IBluetoothGatt.class.getName()), mConnection, 0)) {
-                Log.e(TAG, "Could not bind to Bluetooth Gatt Service");
-            }
-        }
     }
 
     /**
@@ -372,29 +292,75 @@
      */
     /*package*/ void close() {
         if (DBG) Log.d(TAG, "close()");
+        unregisterCallback();
+    }
 
-        unregisterApp();
-        mServiceListener = null;
+    /**
+     * Register an application callback to start using GattServer.
+     *
+     * <p>This is an asynchronous call. The callback is used to notify
+     * success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback GATT callback handler that will receive asynchronous
+     *                 callbacks.
+     * @return true, the callback will be called to notify success or failure,
+     *         false on immediate error
+     */
+    /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
+        if (DBG) Log.d(TAG, "registerCallback()");
+        if (mService == null) {
+            Log.e(TAG, "GATT service not available");
+            return false;
+        }
+        UUID uuid = UUID.randomUUID();
+        if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
 
-        IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
-        if (b != null) {
-            IBluetoothManager mgr = IBluetoothManager.Stub.asInterface(b);
+        synchronized(mServerIfLock) {
+            if (mCallback != null) {
+                Log.e(TAG, "App can register callback only once");
+                return false;
+            }
+
+            mCallback = callback;
             try {
-                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Unable to unregister BluetoothStateChangeCallback", re);
+                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+                mCallback = null;
+                return false;
+            }
+
+            try {
+                mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
+            } catch (InterruptedException e) {
+                Log.e(TAG, "" + e);
+                mCallback = null;
+            }
+
+            if (mServerIf == 0) {
+                mCallback = null;
+                return false;
+            } else {
+                return true;
             }
         }
+    }
 
-        synchronized (mConnection) {
-            if (mService != null) {
-                try {
-                    mService = null;
-                    mContext.unbindService(mConnection);
-                } catch (Exception re) {
-                    Log.e(TAG,"",re);
-                }
-            }
+    /**
+     * Unregister the current application and callbacks.
+     */
+    private void unregisterCallback() {
+        if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
+        if (mService == null || mServerIf == 0) return;
+
+        try {
+            mCallback = null;
+            mService.unregisterServer(mServerIf);
+            mServerIf = 0;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
         }
     }
 
@@ -414,127 +380,11 @@
     }
 
     /**
-     * Register an application callback to start using Gatt.
-     *
-     * <p>This is an asynchronous call. The callback is used to notify
-     * success or failure if the function returns true.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param callback Gatt callback handler that will receive asynchronous
-     *          callbacks.
-     * @return true, if application was successfully registered.
-     */
-    public boolean registerApp(BluetoothGattServerCallback callback) {
-        if (DBG) Log.d(TAG, "registerApp()");
-        if (mService == null) return false;
-
-        mCallback = callback;
-        UUID uuid = UUID.randomUUID();
-        if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
-
-        try {
-            mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Unregister the current application and callbacks.
-     */
-    public void unregisterApp() {
-        if (DBG) Log.d(TAG, "unregisterApp() - mServerIf=" + mServerIf);
-        if (mService == null || mServerIf == 0) return;
-
-        try {
-            mCallback = null;
-            mService.unregisterServer(mServerIf);
-            mServerIf = 0;
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-    }
-
-    /**
-     * Starts a scan for Bluetooth LE devices.
-     *
-     * <p>Results of the scan are reported using the
-     * {@link BluetoothGattServerCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan() {
-        if (DBG) Log.d(TAG, "startScan()");
-        if (mService == null || mServerIf == 0) return false;
-
-        try {
-            mService.startScan(mServerIf, true);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Starts a scan for Bluetooth LE devices, looking for devices that
-     * advertise given services.
-     *
-     * <p>Devices which advertise all specified services are reported using the
-     * {@link BluetoothGattServerCallback#onScanResult} callback.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param serviceUuids Array of services to look for
-     * @return true, if the scan was started successfully
-     */
-    public boolean startScan(UUID[] serviceUuids) {
-        if (DBG) Log.d(TAG, "startScan() - with UUIDs");
-        if (mService == null || mServerIf == 0) return false;
-
-        try {
-            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
-            for(int i = 0; i != uuids.length; ++i) {
-                uuids[i] = new ParcelUuid(serviceUuids[i]);
-            }
-            mService.startScanWithUuids(mServerIf, true, uuids);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Stops an ongoing Bluetooth LE device scan.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     */
-    public void stopScan() {
-        if (DBG) Log.d(TAG, "stopScan()");
-        if (mService == null || mServerIf == 0) return;
-
-        try {
-            mService.stopScan(mServerIf, true);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-    }
-
-    /**
-     * Initiate a connection to a Bluetooth Gatt capable device.
+     * Initiate a connection to a Bluetooth GATT capable device.
      *
      * <p>The connection may not be established right away, but will be
      * completed when the remote device is available. A
-     * {@link BluetoothGattCallback#onConnectionStateChange} callback will be
+     * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
      * invoked when the connection state changes as a result of this function.
      *
      * <p>The autoConnect paramter determines whether to actively connect to
@@ -542,18 +392,17 @@
      * when the remote device is in range/available. Generally, the first ever
      * connection to a device should be direct (autoConnect set to false) and
      * subsequent connections to known devices should be invoked with the
-     * autoConnect parameter set to false.
+     * autoConnect parameter set to true.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param device Remote device to connect to
      * @param autoConnect Whether to directly connect to the remote device (false)
      *                    or to automatically connect as soon as the remote
      *                    device becomes available (true).
      * @return true, if the connection attempt was initiated successfully
      */
     public boolean connect(BluetoothDevice device, boolean autoConnect) {
-        if (DBG) Log.d(TAG, "connect: " + device.getAddress() + ", auto: " + autoConnect);
+        if (DBG) Log.d(TAG, "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
         if (mService == null || mServerIf == 0) return false;
 
         try {
@@ -590,7 +439,7 @@
      * Send a response to a read or write request to a remote device.
      *
      * <p>This function must be invoked in when a remote read/write request
-     * is received by one of these callback methots:
+     * is received by one of these callback methods:
      *
      * <ul>
      *      <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
@@ -662,17 +511,17 @@
     }
 
     /**
-     * Add a service to the list of services to be advertised.
+     * Add a service to the list of services to be hosted.
      *
      * <p>Once a service has been addded to the the list, the service and it's
-     * included characteristics will be advertised by the local device.
+     * included characteristics will be provided by the local device.
      *
-     * <p>If the local device is already advertising services when this function
+     * <p>If the local device has already exposed services when this function
      * is called, a service update notification will be sent to all clients.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param service Service to be added to the list of services advertised
+     * @param service Service to be added to the list of services provided
      *                by this device.
      * @return true, if the service has been added successfully
      */
@@ -705,9 +554,10 @@
 
                 List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
                 for (BluetoothGattDescriptor descriptor: descriptors) {
+                    permission = ((characteristic.getKeySize() - 7) << 12)
+                                        + descriptor.getPermissions();
                     mService.addDescriptor(mServerIf,
-                        new ParcelUuid(descriptor.getUuid()),
-                        descriptor.getPermissions());
+                        new ParcelUuid(descriptor.getUuid()), permission);
                 }
             }
 
@@ -721,11 +571,11 @@
     }
 
     /**
-     * Removes a service from the list of services to be advertised.
+     * Removes a service from the list of services to be provided.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
-     * @param service Service to beremoved.
+     * @param service Service to be removed.
      * @return true, if the service has been removed
      */
     public boolean removeService(BluetoothGattService service) {
@@ -749,7 +599,7 @@
     }
 
     /**
-     * Remove all services from the list of advertised services.
+     * Remove all services from the list of provided services.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      */
     public void clearServices() {
@@ -765,7 +615,7 @@
     }
 
     /**
-     * Returns a list of GATT services offered bu this device.
+     * Returns a list of GATT services offered by this device.
      *
      * <p>An application must call {@link #addService} to add a serice to the
      * list of services offered by this device.
@@ -802,99 +652,40 @@
         return null;
     }
 
+
     /**
-     * Get the current connection state of the profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param device Remote bluetooth device.
-     * @return State of the profile connection. One of
-     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
+     * @throws UnsupportedOperationException
      */
     @Override
     public int getConnectionState(BluetoothDevice device) {
-        if (DBG) Log.d(TAG,"getConnectionState()");
-        if (mService == null) return STATE_DISCONNECTED;
-
-        List<BluetoothDevice> connectedDevices = getConnectedDevices();
-        for(BluetoothDevice connectedDevice : connectedDevices) {
-            if (device.equals(connectedDevice)) {
-                return STATE_CONNECTED;
-            }
-        }
-
-        return STATE_DISCONNECTED;
+        throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
     }
 
     /**
-     * Get connected devices for the Gatt profile.
+     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * with {@link BluetoothProfile#GATT} as argument
      *
-     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getConnectedDevices() {
-        if (DBG) Log.d(TAG,"getConnectedDevices");
-
-        List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return connectedDevices;
-
-        try {
-            connectedDevices = mService.getDevicesMatchingConnectionStates(
-                new int[] { BluetoothProfile.STATE_CONNECTED });
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return connectedDevices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getConnectedDevices instead.");
     }
 
     /**
-     * Get a list of devices that match any of the given connection
-     * states.
+     * Not supported - please use
+     * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
+     * with {@link BluetoothProfile#GATT} as first argument
      *
-     * <p> If none of the devices match any of the given states,
-     * an empty list will be returned.
-     *
-     * <p>This is not specific to any application configuration but represents
-     * the connection state of the local Bluetooth adapter for this profile.
-     * This can be used by applications like status bar which would just like
-     * to know the state of the local adapter.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param states Array of states. States can be one of
-     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
-     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
-     * @return List of devices. The list will be empty on error.
+     * @throws UnsupportedOperationException
      */
     @Override
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
-        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
-
-        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
-        if (mService == null) return devices;
-
-        try {
-            devices = mService.getDevicesMatchingConnectionStates(states);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-        }
-
-        return devices;
+        throw new UnsupportedOperationException
+            ("Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index 4f608ff..f9f1d97 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -22,30 +22,8 @@
 
 /**
  * This abstract class is used to implement {@link BluetoothGattServer} callbacks.
- * @hide
  */
 public abstract class BluetoothGattServerCallback {
-    /**
-     * Callback to inform change in registration state of the  application.
-     *
-     * @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the application
-     *               was successfully registered.
-     */
-    public void onAppRegistered(int status) {
-    }
-
-    /**
-     * Callback reporting an LE device found during a device scan initiated
-     * by the {@link BluetoothGattServer#startScan} 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 onScanResult(BluetoothDevice device, int rssi, byte[] scanRecord) {
-    }
 
     /**
      * Callback indicating when a remote device has been connected or disconnected.
@@ -101,9 +79,9 @@
      * @param value The value the client wants to assign to the characteristic
      */
     public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
-                            BluetoothGattCharacteristic characteristic,
-                            boolean preparedWrite, boolean responseNeeded,
-                            int offset, byte[] value) {
+                                             BluetoothGattCharacteristic characteristic,
+                                             boolean preparedWrite, boolean responseNeeded,
+                                             int offset, byte[] value) {
     }
 
     /**
@@ -118,7 +96,7 @@
      * @param descriptor Descriptor to be read
      */
     public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
-                            int offset, BluetoothGattDescriptor descriptor) {
+                                        int offset, BluetoothGattDescriptor descriptor) {
     }
 
     /**
@@ -137,9 +115,9 @@
      * @param value The value the client wants to assign to the descriptor
      */
     public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
-                            BluetoothGattDescriptor descriptor,
-                            boolean preparedWrite, boolean responseNeeded,
-                            int offset,  byte[] value) {
+                                         BluetoothGattDescriptor descriptor,
+                                         boolean preparedWrite, boolean responseNeeded,
+                                         int offset,  byte[] value) {
     }
 
     /**
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
index 6a3ce66e..39a435b 100644
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ b/core/java/android/bluetooth/BluetoothGattService.java
@@ -22,8 +22,10 @@
 import java.util.UUID;
 
 /**
- * Represents a Bluetooth Gatt Service
- * @hide
+ * Represents a Bluetooth GATT Service
+ *
+ * <p> Gatt Service contains a collection of {@link BluetoothGattCharacteristic},
+ * as well as referenced services.
  */
 public class BluetoothGattService {
 
@@ -81,9 +83,14 @@
 
     /**
      * Create a new BluetoothGattService.
-     * @hide
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param uuid The UUID for this service
+     * @param serviceType The type of this service,
+     *        {@link BluetoothGattService#SERVICE_TYPE_PRIMARY} or
+     *        {@link BluetoothGattService#SERVICE_TYPE_SECONDARY}
      */
-    /*package*/ BluetoothGattService(UUID uuid, int serviceType) {
+    public BluetoothGattService(UUID uuid, int serviceType) {
         mDevice = null;
         mUuid = uuid;
         mInstanceId = 0;
@@ -115,11 +122,28 @@
     }
 
     /**
-     * Add a characteristic to this service.
-     * @hide
+     * Add an included service to this service.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param service The service to be added
+     * @return true, if the included service was added to the service
      */
-    /*package*/ void addCharacteristic(BluetoothGattCharacteristic characteristic) {
+    public boolean addService(BluetoothGattService service) {
+        mIncludedServices.add(service);
+        return true;
+    }
+
+    /**
+     * Add a characteristic to this service.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param characteristic The characteristics to be added
+     * @return true, if the characteristic was added to the service
+     */
+    public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
         mCharacteristics.add(characteristic);
+        characteristic.setService(this);
+        return true;
     }
 
     /**
@@ -136,6 +160,15 @@
     }
 
     /**
+     * Force the instance ID.
+     * This is needed for conformance testing only.
+     * @hide
+     */
+    public void setInstanceId(int instanceId) {
+        mInstanceId = instanceId;
+    }
+
+    /**
      * Get the handle count override (conformance testing.
      * @hide
      */
@@ -144,6 +177,15 @@
     }
 
     /**
+     * Force the number of handles to reserve for this service.
+     * This is needed for conformance testing only.
+     * @hide
+     */
+    public void setHandles(int handles) {
+        mHandles = handles;
+    }
+
+    /**
      * Add an included service to the internal map.
      * @hide
      */
@@ -153,7 +195,6 @@
 
     /**
      * Returns the UUID of this service
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return UUID of this service
      */
@@ -168,8 +209,6 @@
      * (ex. multiple battery services for different batteries), the instance
      * ID is used to distuinguish services.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
      * @return Instance ID of this service
      */
     public int getInstanceId() {
@@ -178,15 +217,13 @@
 
     /**
      * Get the type of this service (primary/secondary)
-     * @hide
      */
     public int getType() {
         return mServiceType;
     }
 
     /**
-     * Get the list of included Gatt services for this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     * Get the list of included GATT services for this service.
      *
      * @return List of included services or empty list if no included services
      *         were discovered.
@@ -197,7 +234,6 @@
 
     /**
      * Returns a list of characteristics included in this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @return Characteristics included in this service
      */
@@ -217,9 +253,7 @@
      * UUID, the first instance of a characteristic with the given UUID
      * is returned.
      *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @return Gatt characteristic object or null if no characteristic with the
+     * @return GATT characteristic object or null if no characteristic with the
      *         given UUID was found.
      */
     public BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
old mode 100755
new mode 100644
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
old mode 100755
new mode 100644
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
new file mode 100644
index 0000000..19083b5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -0,0 +1,219 @@
+/*
+ * 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.content.Context;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * High level manager used to obtain an instance of an {@link BluetoothAdapter}
+ * and to conduct overall Bluetooth Management.
+ * <p>
+ * Use {@link android.content.Context#getSystemService(java.lang.String)}
+ * with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager},
+ * then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}.
+ * <p>
+ * Alternately, you can just call the static helper
+ * {@link BluetoothAdapter#getDefaultAdapter()}.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using BLUETOOTH, read the
+ * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
+ * </div>
+ *
+ * @see Context#getSystemService
+ * @see BluetoothAdapter#getDefaultAdapter()
+ */
+public final class BluetoothManager {
+    private static final String TAG = "BluetoothManager";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = true;
+
+    private final BluetoothAdapter mAdapter;
+
+    /**
+     * @hide
+     */
+    public BluetoothManager(Context context) {
+        context = context.getApplicationContext();
+        if (context == null) {
+            throw new IllegalArgumentException(
+                    "context not associated with any application (using a mock context?)");
+        }
+        // Legacy api - getDefaultAdapter does not take in the context
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
+    }
+
+    /**
+     * Get the default BLUETOOTH Adapter for this device.
+     *
+     * @return the default BLUETOOTH Adapter
+     */
+    public BluetoothAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Get the current connection state of the profile to the remote device.
+     *
+     * <p>This is not specific to any application configuration but represents
+     * the connection state of the local Bluetooth adapter for certain profile.
+     * This can be used by applications like status bar which would just like
+     * to know the state of Bluetooth.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device Remote bluetooth device.
+     * @param profile GATT or GATT_SERVER
+     * @return State of the profile connection. One of
+     *         {@link BluetoothProfile#STATE_CONNECTED}, {@link BluetoothProfile#STATE_CONNECTING},
+     *         {@link BluetoothProfile#STATE_DISCONNECTED},
+     *         {@link BluetoothProfile#STATE_DISCONNECTING}
+     */
+    public int getConnectionState(BluetoothDevice device, int profile) {
+        if (DBG) Log.d(TAG,"getConnectionState()");
+
+        List<BluetoothDevice> connectedDevices = getConnectedDevices(profile);
+        for(BluetoothDevice connectedDevice : connectedDevices) {
+            if (device.equals(connectedDevice)) {
+                return BluetoothProfile.STATE_CONNECTED;
+            }
+        }
+
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    /**
+     * Get connected devices for the specified profile.
+     *
+     * <p> Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED}
+     *
+     * <p>This is not specific to any application configuration but represents
+     * the connection state of Bluetooth for this profile.
+     * This can be used by applications like status bar which would just like
+     * to know the state of Bluetooth.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param profile GATT or GATT_SERVER
+     * @return List of devices. The list will be empty on error.
+     */
+    public List<BluetoothDevice> getConnectedDevices(int profile) {
+        if (DBG) Log.d(TAG,"getConnectedDevices");
+        if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
+            throw new IllegalArgumentException("Profile not supported: " + profile);
+        }
+
+        List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
+
+        try {
+            IBluetoothManager managerService = mAdapter.getBluetoothManager();
+            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            if (iGatt == null) return connectedDevices;
+
+            connectedDevices = iGatt.getDevicesMatchingConnectionStates(
+                new int[] { BluetoothProfile.STATE_CONNECTED });
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+
+        return connectedDevices;
+    }
+
+    /**
+     * 
+     * Get a list of devices that match any of the given connection
+     * states.
+     *
+     * <p> If none of the devices match any of the given states,
+     * an empty list will be returned.
+     *
+     * <p>This is not specific to any application configuration but represents
+     * the connection state of the local Bluetooth adapter for this profile.
+     * This can be used by applications like status bar which would just like
+     * to know the state of the local adapter.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param profile GATT or GATT_SERVER
+     * @param states Array of states. States can be one of
+     *        {@link BluetoothProfile#STATE_CONNECTED}, {@link BluetoothProfile#STATE_CONNECTING},
+     *        {@link BluetoothProfile#STATE_DISCONNECTED},
+     *        {@link BluetoothProfile#STATE_DISCONNECTING},
+     * @return List of devices. The list will be empty on error.
+     */
+    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) {
+        if (DBG) Log.d(TAG,"getDevicesMatchingConnectionStates");
+
+        if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
+            throw new IllegalArgumentException("Profile not supported: " + profile);
+        }
+
+        List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
+
+        try {
+            IBluetoothManager managerService = mAdapter.getBluetoothManager();
+            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            if (iGatt == null) return devices;
+            devices = iGatt.getDevicesMatchingConnectionStates(states);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+        }
+
+        return devices;
+    }
+
+    /**
+     * Open a GATT Server
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as the results of any other GATT server operations.
+     * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+     * to conduct GATT server operations.
+     * @param context App context
+     * @param callback GATT server callback handler that will receive asynchronous callbacks.
+     * @return BluetoothGattServer instance
+     */
+    public BluetoothGattServer openGattServer(Context context,
+                                              BluetoothGattServerCallback callback) {
+        if (context == null || callback == null) {
+            throw new IllegalArgumentException("null parameter: " + context + " " + callback);
+        }
+
+        // TODO(Bluetooth) check whether platform support BLE
+        //     Do the check here or in GattServer?
+
+        try {
+            IBluetoothManager managerService = mAdapter.getBluetoothManager();
+            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            if (iGatt == null) {
+                Log.e(TAG, "Fail to get GATT Server connection");
+                return null;
+            }
+            BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt);
+            Boolean regStatus = mGattServer.registerCallback(callback);
+            return regStatus? mGattServer : null;
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
old mode 100755
new mode 100644
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 9ee202a..43079f4 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -89,13 +89,11 @@
 
     /**
      * GATT
-     * @hide
      */
     static public final int GATT = 7;
 
     /**
      * GATT_SERVER
-     * @hide
      */
     static public final int GATT_SERVER = 8;
 
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 3ba4f26..81c0a6a 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -21,6 +21,7 @@
 import android.os.INetworkManagementService;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.DhcpResults;
 import android.net.LinkCapabilities;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
@@ -28,7 +29,10 @@
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
+import android.os.Messenger;
+import android.text.TextUtils;
 import android.util.Log;
 import java.net.InterfaceAddress;
 import android.net.LinkAddress;
@@ -36,8 +40,11 @@
 import java.net.Inet4Address;
 import android.os.SystemProperties;
 
+import com.android.internal.util.AsyncChannel;
+
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * This class tracks the data connection associated with Bluetooth
@@ -51,24 +58,29 @@
     private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
     private static final String TAG = "BluetoothTethering";
     private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+    private static final boolean VDBG = true;
 
     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
 
+    private final Object mLinkPropertiesLock = new Object();
     private LinkProperties mLinkProperties;
+
     private LinkCapabilities mLinkCapabilities;
+
+    private final Object mNetworkInfoLock = new Object();
     private NetworkInfo mNetworkInfo;
 
     private BluetoothPan mBluetoothPan;
-    private static String mIface;
-    private Thread mDhcpThread;
+    private static String mRevTetheredIface;
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
-    private Context mContext;
-    public static BluetoothTetheringDataTracker sInstance;
+    protected Context mContext;
+    private static BluetoothTetheringDataTracker sInstance;
+    private BtdtHandler mBtdtHandler;
+    private AtomicReference<AsyncChannel> mAsyncChannel = new AtomicReference<AsyncChannel>(null);
 
     private BluetoothTetheringDataTracker() {
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
@@ -108,6 +120,7 @@
         if (adapter != null) {
             adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
         }
+        mBtdtHandler = new BtdtHandler(target.getLooper(), this);
     }
 
     private BluetoothProfile.ServiceListener mProfileServiceListener =
@@ -224,15 +237,19 @@
     /**
      * Fetch NetworkInfo for the network
      */
-    public synchronized NetworkInfo getNetworkInfo() {
-        return mNetworkInfo;
+    public NetworkInfo getNetworkInfo() {
+        synchronized (mNetworkInfoLock) {
+            return new NetworkInfo(mNetworkInfo);
+        }
     }
 
     /**
      * Fetch LinkProperties for the network
      */
-    public synchronized LinkProperties getLinkProperties() {
-        return new LinkProperties(mLinkProperties);
+    public LinkProperties getLinkProperties() {
+        synchronized (mLinkPropertiesLock) {
+            return new LinkProperties(mLinkProperties);
+        }
     }
 
    /**
@@ -286,91 +303,131 @@
         return count;
     }
 
-
-    private boolean readLinkProperty(String iface) {
-        String DhcpPrefix = "dhcp." + iface + ".";
-        String ip = SystemProperties.get(DhcpPrefix + "ipaddress");
-        String dns1 = SystemProperties.get(DhcpPrefix + "dns1");
-        String dns2 = SystemProperties.get(DhcpPrefix + "dns2");
-        String gateway = SystemProperties.get(DhcpPrefix + "gateway");
-        String mask = SystemProperties.get(DhcpPrefix + "mask");
-        if(ip.isEmpty() || gateway.isEmpty()) {
-            Log.e(TAG, "readLinkProperty, ip: " +  ip + ", gateway: " + gateway + ", can not be empty");
-            return false;
+    void startReverseTether(final LinkProperties linkProperties) {
+        if (linkProperties == null || TextUtils.isEmpty(linkProperties.getInterfaceName())) {
+            Log.e(TAG, "attempted to reverse tether with empty interface");
+            return;
         }
-        int PrefixLen = countPrefixLength(NetworkUtils.numericToInetAddress(mask).getAddress());
-        mLinkProperties.addLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(ip), PrefixLen));
-        RouteInfo ri = new RouteInfo(NetworkUtils.numericToInetAddress(gateway));
-        mLinkProperties.addRoute(ri);
-        if(!dns1.isEmpty())
-            mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns1));
-        if(!dns2.isEmpty())
-            mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns2));
-        mLinkProperties.setInterfaceName(iface);
-        return true;
-    }
-    public synchronized void startReverseTether(String iface) {
-        mIface = iface;
-        if (DBG) Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
-         mDhcpThread = new Thread(new Runnable() {
+        synchronized (mLinkPropertiesLock) {
+            if (mLinkProperties.getInterfaceName() != null) {
+                Log.e(TAG, "attempted to reverse tether while already in process");
+                return;
+            }
+            mLinkProperties = linkProperties;
+        }
+        Thread dhcpThread = new Thread(new Runnable() {
             public void run() {
-                //TODO(): Add callbacks for failure and success case.
                 //Currently this thread runs independently.
-                if (DBG) Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
-                String DhcpResultName = "dhcp." + mIface + ".result";;
-                String result = "";
-                if (VDBG) Log.d(TAG, "waiting for change of sys prop dhcp result: " + DhcpResultName);
-                for(int i = 0; i < 30*5; i++) {
-                    try { Thread.sleep(200); } catch (InterruptedException ie) { return;}
-                    result = SystemProperties.get(DhcpResultName);
-                    if (VDBG) Log.d(TAG, "read " + DhcpResultName + ": " + result);
-                    if(result.equals("failed")) {
-                        Log.e(TAG, "startReverseTether, failed to start dhcp service");
+                DhcpResults dhcpResults = new DhcpResults();
+                boolean success = NetworkUtils.runDhcp(linkProperties.getInterfaceName(),
+                        dhcpResults);
+                synchronized (mLinkPropertiesLock) {
+                    if (linkProperties.getInterfaceName() != mLinkProperties.getInterfaceName()) {
+                        Log.e(TAG, "obsolete DHCP run aborted");
                         return;
                     }
-                    if(result.equals("ok")) {
-                        if (VDBG) Log.d(TAG, "startReverseTether, dhcp resut: " + result);
-                        if(readLinkProperty(mIface)) {
-
-                            mNetworkInfo.setIsAvailable(true);
-                            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-
-                            if (VDBG) Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
-                            if(mCsHandler != null) {
-                                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
-                                msg.sendToTarget();
-
-                                msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-                                msg.sendToTarget();
-                            }
-                        }
+                    if (!success) {
+                        Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
                         return;
                     }
+                    mLinkProperties = dhcpResults.linkProperties;
+                    synchronized (mNetworkInfoLock) {
+                        mNetworkInfo.setIsAvailable(true);
+                        mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+                        if (mCsHandler != null) {
+                            Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
+                                    new NetworkInfo(mNetworkInfo));
+                            msg.sendToTarget();
+                       }
+                    }
+                    return;
                 }
-                Log.e(TAG, "startReverseTether, dhcp failed, resut: " + result);
             }
         });
-        mDhcpThread.start();
+        dhcpThread.start();
     }
 
-    public synchronized void stopReverseTether() {
-        //NetworkUtils.stopDhcp(iface);
-        if(mDhcpThread != null && mDhcpThread.isAlive()) {
-            mDhcpThread.interrupt();
-            try { mDhcpThread.join(); } catch (InterruptedException ie) { return; }
+    void stopReverseTether() {
+        synchronized (mLinkPropertiesLock) {
+            if (TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
+                Log.e(TAG, "attempted to stop reverse tether with nothing tethered");
+                return;
+            }
+            NetworkUtils.stopDhcp(mLinkProperties.getInterfaceName());
+            mLinkProperties.clear();
+            synchronized (mNetworkInfoLock) {
+                mNetworkInfo.setIsAvailable(false);
+                mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+
+                if (mCsHandler != null) {
+                    mCsHandler.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)).
+                            sendToTarget();
+                }
+            }
         }
-        mLinkProperties.clear();
-        mNetworkInfo.setIsAvailable(false);
-        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
-
-        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
-        msg.sendToTarget();
-
-        msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
-        msg.sendToTarget();
     }
 
     public void setDependencyMet(boolean met) {
         // not supported on this network
     }
+
+    @Override
+    public void addStackedLink(LinkProperties link) {
+        mLinkProperties.addStackedLink(link);
+    }
+
+    @Override
+    public void removeStackedLink(LinkProperties link) {
+        mLinkProperties.removeStackedLink(link);
+    }
+
+    static class BtdtHandler extends Handler {
+        private AsyncChannel mStackChannel;
+        private final BluetoothTetheringDataTracker mBtdt;
+
+        BtdtHandler(Looper looper, BluetoothTetheringDataTracker parent) {
+            super(looper);
+            mBtdt = parent;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (VDBG) Log.d(TAG, "got CMD_CHANNEL_HALF_CONNECTED");
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        AsyncChannel ac = (AsyncChannel)msg.obj;
+                        if (mBtdt.mAsyncChannel.compareAndSet(null, ac) == false) {
+                            Log.e(TAG, "Trying to set mAsyncChannel twice!");
+                        } else {
+                            ac.sendMessage(
+                                    AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                        }
+                    }
+                    break;
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                    if (VDBG) Log.d(TAG, "got CMD_CHANNEL_DISCONNECTED");
+                    mBtdt.stopReverseTether();
+                    mBtdt.mAsyncChannel.set(null);
+                    break;
+                case NetworkStateTracker.EVENT_NETWORK_CONNECTED:
+                    LinkProperties linkProperties = (LinkProperties)(msg.obj);
+                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_CONNECTED, " + linkProperties);
+                    mBtdt.startReverseTether(linkProperties);
+                    break;
+                case NetworkStateTracker.EVENT_NETWORK_DISCONNECTED:
+                    linkProperties = (LinkProperties)(msg.obj);
+                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
+                    mBtdt.stopReverseTether();
+                    break;
+            }
+        }
+    }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        if (messenger != null) {
+            new AsyncChannel().connect(mContext, mBtdtHandler, messenger);
+        }
+    }
 }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index d016c26..80806f9 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -60,6 +60,7 @@
     int getBondState(in BluetoothDevice device);
 
     String getRemoteName(in BluetoothDevice device);
+    int getRemoteType(in BluetoothDevice device);
     String getRemoteAlias(in BluetoothDevice device);
     boolean setRemoteAlias(in BluetoothDevice device, in String name);
     int getRemoteClass(in BluetoothDevice device);
diff --git a/core/java/android/bluetooth/IBluetoothInputDevice.aidl b/core/java/android/bluetooth/IBluetoothInputDevice.aidl
old mode 100755
new mode 100644
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
old mode 100755
new mode 100644
index ed8777c..493d2f8
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothManagerCallback;
 import android.bluetooth.IBluetoothStateChangeCallback;
 
@@ -35,6 +36,7 @@
     boolean enable();
     boolean enableNoAutoConnect();
     boolean disable(boolean persist);
+    IBluetoothGatt getBluetoothGatt();
 
     String getAddress();
     String getName();
diff --git a/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java b/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java
deleted file mode 100644
index c05abb2..0000000
--- a/core/java/android/bluetooth/MutableBluetoothGattCharacteristic.java
+++ /dev/null
@@ -1,67 +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 java.util.ArrayList;
-import java.util.IllegalFormatConversionException;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Mutable variant of a Bluetooth Gatt Characteristic
- * @hide
- */
-public class MutableBluetoothGattCharacteristic extends BluetoothGattCharacteristic {
-
-    /**
-     * Create a new MutableBluetoothGattCharacteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param uuid The UUID for this characteristic
-     * @param properties Properties of this characteristic
-     * @param permissions Permissions for this characteristic
-     */
-    public MutableBluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
-        super(null, uuid, 0, properties, permissions);
-    }
-
-    /**
-     * Adds a descriptor to this characteristic.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param descriptor Descriptor to be added to this characteristic.
-     */
-    public void addDescriptor(MutableBluetoothGattDescriptor descriptor) {
-        mDescriptors.add(descriptor);
-        descriptor.setCharacteristic(this);
-    }
-
-    /**
-     * Set the desired key size.
-     * @hide
-     */
-    public void setKeySize(int keySize) {
-        mKeySize = keySize;
-    }
-
-    /**
-     * Sets the service associated with this device.
-     * @hide
-     */
-    /*package*/ void setService(BluetoothGattService service) {
-        mService = service;
-    }
-}
diff --git a/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java b/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java
deleted file mode 100644
index e455392..0000000
--- a/core/java/android/bluetooth/MutableBluetoothGattDescriptor.java
+++ /dev/null
@@ -1,45 +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 java.util.UUID;
-
-/**
- * Mutable variant of a Bluetooth Gatt Descriptor
- * @hide
- */
-public class MutableBluetoothGattDescriptor extends BluetoothGattDescriptor {
-
-    /**
-     * Create a new BluetoothGattDescriptor.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param uuid The UUID for this descriptor
-     * @param permissions Permissions for this descriptor
-     */
-    public MutableBluetoothGattDescriptor(UUID uuid, int permissions) {
-        super(null, uuid, permissions);
-    }
-
-    /**
-     * Set the back-reference to the associated characteristic
-     * @hide
-     */
-    /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
-        mCharacteristic = characteristic;
-    }
-}
diff --git a/core/java/android/bluetooth/MutableBluetoothGattService.java b/core/java/android/bluetooth/MutableBluetoothGattService.java
deleted file mode 100644
index 927f5ab..0000000
--- a/core/java/android/bluetooth/MutableBluetoothGattService.java
+++ /dev/null
@@ -1,83 +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;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Represents a Bluetooth Gatt Service
- * @hide
- */
-public class MutableBluetoothGattService extends BluetoothGattService {
-
-    /**
-     * Create a new MutableBluetoothGattService.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param uuid The UUID for this service
-     * @param serviceType The type of this service (primary/secondary)
-     */
-    public MutableBluetoothGattService(UUID uuid, int serviceType) {
-        super(uuid, serviceType);
-    }
-
-    /**
-     * Add an included service to this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param service The service to be added
-     * @return true, if the included service was added to the service
-     */
-    public boolean addService(BluetoothGattService service) {
-        mIncludedServices.add(service);
-        return true;
-    }
-
-    /**
-     * Add a characteristic to this service.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param characteristic The characteristics to be added
-     * @return true, if the characteristic was added to the service
-     */
-    public boolean addCharacteristic(MutableBluetoothGattCharacteristic characteristic) {
-        mCharacteristics.add(characteristic);
-        characteristic.setService(this);
-        return true;
-    }
-
-    /**
-     * Force the instance ID.
-     * This is needed for conformance testing only.
-     * @hide
-     */
-    public void setInstanceId(int instanceId) {
-        mInstanceId = instanceId;
-    }
-
-    /**
-     * Force the number of handles to reserve for this service.
-     * This is needed for conformance testing only.
-     * @hide
-     */
-    public void setHandles(int handles) {
-        mHandles = handles;
-    }
-}
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 188c786..612c67f 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -231,6 +231,7 @@
         onCanceled(data);
         if (mCancellingTask == task) {
             if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
+            rollbackContentChanged();
             mLastLoadCompleteTime = SystemClock.uptimeMillis();
             mCancellingTask = null;
             if (DEBUG) Slog.v(TAG, "Delivering cancellation");
@@ -248,6 +249,7 @@
                 // This cursor has been abandoned; just cancel the new data.
                 onCanceled(data);
             } else {
+                commitContentChanged();
                 mLastLoadCompleteTime = SystemClock.uptimeMillis();
                 mTask = null;
                 if (DEBUG) Slog.v(TAG, "Delivering result");
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 4f42d50..9a32fdf 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -520,7 +520,7 @@
         IActivityManager am = ActivityManagerNative.getDefault();
         IBinder binder = null;
         try {
-            service.setAllowFds(false);
+            service.prepareToLeaveProcess();
             binder = am.peekService(service, service.resolveTypeIfNeeded(
                     myContext.getContentResolver()));
         } catch (RemoteException e) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 88f1a3d..50c4fed 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.StrictMode;
 import android.text.Html;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
@@ -790,6 +791,24 @@
         return mItems.get(index);
     }
 
+    /**
+     * Prepare this {@link ClipData} to leave an app process.
+     *
+     * @hide
+     */
+    public void prepareToLeaveProcess() {
+        final int size = mItems.size();
+        for (int i = 0; i < size; i++) {
+            final Item item = mItems.get(i);
+            if (item.mIntent != null) {
+                item.mIntent.prepareToLeaveProcess();
+            }
+            if (item.mUri != null && StrictMode.vmFileUriExposureEnabled()) {
+                item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+            }
+        }
+    }
+
     @Override
     public String toString() {
         StringBuilder b = new StringBuilder(128);
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 88a4229..69f9d4a 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.StrictMode;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -118,6 +119,9 @@
      */
     public void setPrimaryClip(ClipData clip) {
         try {
+            if (clip != null) {
+                clip.prepareToLeaveProcess();
+            }
             getService().setPrimaryClip(clip, mContext.getBasePackageName());
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 8aef405..cf627d7 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -609,7 +609,7 @@
         // selection statement with a dummy one that will always be false.
         // This way we will get a cursor back that has the correct structure
         // but contains no rows.
-        if (selection == null) {
+        if (selection == null || selection.isEmpty()) {
             selection = "'A' = 'B'";
         } else {
             selection = "'A' = 'B' AND (" + selection + ")";
@@ -1256,6 +1256,13 @@
      * interfaces that are cheaper and/or unnatural for a table-like
      * model.
      *
+     * <p class="note"><strong>WARNING:</strong> The framework does no permission checking
+     * on this entry into the content provider besides the basic ability for the application
+     * to get access to the provider at all.  For example, it has no idea whether the call
+     * being executed may read or write data in the provider, so can't enforce those
+     * individual permissions.  Any implementation of this method <strong>must</strong>
+     * do its own permission checks on incoming calls to make sure they are allowed.</p>
+     *
      * @param method method name to call.  Opaque to framework, but should not be {@code null}.
      * @param arg provider-defined String argument.  May be {@code null}.
      * @param extras provider-defined Bundle argument.  May be {@code null}.
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8a9eed2..03e241a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -45,6 +45,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 
 /**
  * Interface to global information about an application environment.  This is
@@ -255,6 +256,12 @@
      * Return the Looper for the main thread of the current process.  This is
      * the thread used to dispatch calls to application components (activities,
      * services, etc).
+     * <p>
+     * By definition, this method returns the same result as would be obtained
+     * by calling {@link Looper#getMainLooper() Looper.getMainLooper()}.
+     * </p>
+     *
+     * @return The main looper.
      */
     public abstract Looper getMainLooper();
 
@@ -286,6 +293,15 @@
     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
@@ -2193,7 +2209,6 @@
      * {@link android.bluetooth.BluetoothAdapter} for using Bluetooth.
      *
      * @see #getSystemService
-     * @hide
      */
     public static final String BLUETOOTH_SERVICE = "bluetooth";
 
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 4e89dec..5d7d677 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -68,7 +68,7 @@
                 try {
                     // Ensure the cursor window is filled.
                     cursor.getCount();
-                    registerContentObserver(cursor, mObserver);
+                    cursor.registerContentObserver(mObserver);
                 } catch (RuntimeException ex) {
                     cursor.close();
                     throw ex;
@@ -93,14 +93,6 @@
         }
     }
 
-    /**
-     * Registers an observer to get notifications from the content provider
-     * when the cursor needs to be refreshed.
-     */
-    void registerContentObserver(Cursor cursor, ContentObserver observer) {
-        cursor.registerContentObserver(mObserver);
-    }
-
     /* Runs on the UI thread */
     @Override
     public void deliverResult(Cursor cursor) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 60e9f58..97ad7dd 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.StrictMode;
 import android.util.AttributeSet;
 import android.util.Log;
 
@@ -1164,12 +1165,13 @@
      * additional optional contextual information about where the user was when they requested
      * the voice assist.
      * Output: nothing.
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
 
     /**
-     * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
+     * An optional field on {@link #ACTION_ASSIST}
      * containing the name of the current foreground application package at the time
      * the assist was invoked.
      */
@@ -1177,7 +1179,7 @@
             = "android.intent.extra.ASSIST_PACKAGE";
 
     /**
-     * An optional field on {@link #ACTION_ASSIST} and {@link #ACTION_VOICE_ASSIST}
+     * An optional field on {@link #ACTION_ASSIST}
      * containing additional contextual information supplied by the current
      * foreground app at the time of the assist request.  This is a {@link Bundle} of
      * additional data.
@@ -2414,6 +2416,18 @@
             "android.intent.action.PRE_BOOT_COMPLETED";
 
     /**
+     * Broadcast to a specific application to query any supported restrictions to impose
+     * on restricted users. The response should contain an extra {@link #EXTRA_RESTRICTIONS},
+     * 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.
+     * @see RestrictionEntry
+     */
+    public static final String ACTION_GET_RESTRICTION_ENTRIES =
+            "android.intent.action.GET_RESTRICTION_ENTRIES";
+
+    /**
      * Sent the first time a user is starting, to allow system apps to
      * perform one time initialization.  (This will not be seen by third
      * party applications because a newly initialized user does not have any
@@ -2565,6 +2579,14 @@
     public static final String ACTION_SHOW_BRIGHTNESS_DIALOG =
             "android.intent.action.SHOW_BRIGHTNESS_DIALOG";
 
+    /**
+     * Broadcast Action:  A global button was pressed.  Includes a single
+     * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
+     * caused the broadcast.
+     * @hide
+     */
+    public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
@@ -3145,6 +3167,19 @@
     public static final String EXTRA_USER_HANDLE =
             "android.intent.extra.user_handle";
 
+    /**
+     * Extra used in the response from a BroadcastReceiver that handles
+     * {@link #ACTION_GET_RESTRICTION_ENTRIES}.
+     */
+    public static final String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+
+    /**
+     * Extra used in the response from a BroadcastReceiver that handles
+     * {@link #ACTION_GET_RESTRICTION_ENTRIES}.
+     */
+    public static final String EXTRA_RESTRICTIONS_INTENT =
+            "android.intent.extra.restrictions_intent";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
@@ -6932,6 +6967,32 @@
     }
 
     /**
+     * Prepare this {@link Intent} to leave an app process.
+     *
+     * @hide
+     */
+    public void prepareToLeaveProcess() {
+        setAllowFds(false);
+
+        if (mSelector != null) {
+            mSelector.prepareToLeaveProcess();
+        }
+        if (mClipData != null) {
+            mClipData.prepareToLeaveProcess();
+        }
+
+        if (mData != null && StrictMode.vmFileUriExposureEnabled()) {
+            // There are several ACTION_MEDIA_* broadcasts that send file://
+            // Uris, so only check common actions.
+            if (ACTION_VIEW.equals(mAction) ||
+                    ACTION_EDIT.equals(mAction) ||
+                    ACTION_ATTACH_DATA.equals(mAction)) {
+                mData.checkFileUriExposed("Intent.getData()");
+            }
+        }
+    }
+
+    /**
      * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
      * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
      * intents in {@link #ACTION_CHOOSER}.
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 3052414..911e49c 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -58,6 +58,7 @@
     boolean mAbandoned = false;
     boolean mReset = true;
     boolean mContentChanged = false;
+    boolean mProcessingChange = false;
 
     /**
      * An implementation of a ContentObserver that takes care of connecting
@@ -439,6 +440,7 @@
         mStarted = false;
         mAbandoned = false;
         mContentChanged = false;
+        mProcessingChange = false;
     }
 
     /**
@@ -458,9 +460,34 @@
     public boolean takeContentChanged() {
         boolean res = mContentChanged;
         mContentChanged = false;
+        mProcessingChange |= res;
         return res;
     }
-    
+
+    /**
+     * Commit that you have actually fully processed a content change that
+     * was returned by {@link #takeContentChanged}.  This is for use with
+     * {@link #rollbackContentChanged()} to handle situations where a load
+     * is cancelled.  Call this when you have completely processed a load
+     * without it being cancelled.
+     */
+    public void commitContentChanged() {
+        mProcessingChange = false;
+    }
+
+    /**
+     * Report that you have abandoned the processing of a content change that
+     * was returned by {@link #takeContentChanged()} and would like to rollback
+     * to the state where there is again a pending content change.  This is
+     * to handle the case where a data load due to a content change has been
+     * canceled before its data was delivered back to the loader.
+     */
+    public void rollbackContentChanged() {
+        if (mProcessingChange) {
+            mContentChanged = true;
+        }
+    }
+
     /**
      * Called when {@link ForceLoadContentObserver} detects a change.  The
      * default implementation checks to see if the loader is currently started;
@@ -512,9 +539,14 @@
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         writer.print(prefix); writer.print("mId="); writer.print(mId);
                 writer.print(" mListener="); writer.println(mListener);
-        writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
-                writer.print(" mContentChanged="); writer.print(mContentChanged);
-                writer.print(" mAbandoned="); writer.print(mAbandoned);
-                writer.print(" mReset="); writer.println(mReset);
+        if (mStarted || mContentChanged || mProcessingChange) {
+            writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
+                    writer.print(" mContentChanged="); writer.print(mContentChanged);
+                    writer.print(" mProcessingChange="); writer.println(mProcessingChange);
+        }
+        if (mAbandoned || mReset) {
+            writer.print(prefix); writer.print("mAbandoned="); writer.print(mAbandoned);
+                    writer.print(" mReset="); writer.println(mReset);
+        }
     }
 }
\ No newline at end of file
diff --git a/core/java/android/content/RestrictionEntry.aidl b/core/java/android/content/RestrictionEntry.aidl
new file mode 100644
index 0000000..b93eee3
--- /dev/null
+++ b/core/java/android/content/RestrictionEntry.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** 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.
+*/
+
+package android.content;
+
+parcelable RestrictionEntry;
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
new file mode 100644
index 0000000..af90385
--- /dev/null
+++ b/core/java/android/content/RestrictionEntry.java
@@ -0,0 +1,412 @@
+/*
+ * 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.content;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Inherited;
+
+/**
+ * Applications can expose restrictions for a restricted user on a
+ * multiuser device. The administrator can configure these restrictions that will then be
+ * applied to the restricted user. Each RestrictionsEntry is one configurable restriction.
+ * <p/>
+ * Any application that chooses to expose such restrictions does so by implementing a
+ * receiver that handles the {@link Intent#ACTION_GET_RESTRICTION_ENTRIES} action.
+ * The receiver then returns a result bundle that contains an entry called "restrictions", whose
+ * value is an ArrayList<RestrictionsEntry>.
+ */
+public class RestrictionEntry implements Parcelable {
+
+    /**
+     * A type of restriction. Use this type for information that needs to be transferred across
+     * but shouldn't be presented to the user in the UI. Stores a single String value.
+     */
+    public static final int TYPE_NULL         = 0;
+
+    /**
+     * A type of restriction. Use this for storing a boolean value, typically presented as
+     * a checkbox in the UI.
+     */
+    public static final int TYPE_BOOLEAN      = 1;
+
+    /**
+     * A type of restriction. Use this for storing a string value, typically presented as
+     * a single-select list. Call {@link #setChoiceEntries(String[])} and
+     * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
+     * and the corresponding values, respectively.
+     */
+    public static final int TYPE_CHOICE       = 2;
+
+    /**
+     * A type of restriction. Use this for storing a string value, typically presented as
+     * a single-select list. Call {@link #setChoiceEntries(String[])} and
+     * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
+     * and the corresponding values, respectively.
+     * The presentation could imply that values in lower array indices are included when a
+     * particular value is chosen.
+     */
+    public static final int TYPE_CHOICE_LEVEL = 3;
+
+    /**
+     * A type of restriction. Use this for presenting a multi-select list where more than one
+     * entry can be selected, such as for choosing specific titles to white-list.
+     * Call {@link #setChoiceEntries(String[])} and
+     * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
+     * and the corresponding values, respectively.
+     * Use {@link #getAllSelectedStrings()} and {@link #setAllSelectedStrings(String[])} to
+     * manipulate the selections.
+     */
+    public static final int TYPE_MULTI_SELECT = 4;
+
+    /** The type of restriction. */
+    private int type;
+
+    /** The unique key that identifies the restriction. */
+    private String key;
+
+    /** The user-visible title of the restriction. */
+    private String title;
+
+    /** The user-visible secondary description of the restriction. */
+    private String description;
+
+    /** The user-visible set of choices used for single-select and multi-select lists. */
+    private String [] choices;
+
+    /** The values corresponding to the user-visible choices. The value(s) of this entry will
+     * one or more of these, returned by {@link #getAllSelectedStrings()} and
+     * {@link #getSelectedString()}.
+     */
+    private String [] values;
+
+    /* The chosen value, whose content depends on the type of the restriction. */
+    private String currentValue;
+
+    /* List of selected choices in the multi-select case. */
+    private String[] currentValues;
+
+    /**
+     * Constructor for {@link #TYPE_CHOICE} and {@link #TYPE_CHOICE_LEVEL} types.
+     * @param key the unique key for this restriction
+     * @param selectedString the current value
+     */
+    public RestrictionEntry(String key, String selectedString) {
+        this.key = key;
+        this.currentValue = selectedString;
+    }
+
+    /**
+     * Constructor for {@link #TYPE_BOOLEAN} type.
+     * @param key the unique key for this restriction
+     * @param selectedState whether this restriction is selected or not
+     */
+    public RestrictionEntry(String key, boolean selectedState) {
+        this.key = key;
+        setSelectedState(selectedState);
+    }
+
+    /**
+     * Constructor for {@link #TYPE_MULTI_SELECT} type.
+     * @param key the unique key for this restriction
+     * @param selectedStrings the list of values that are currently selected
+     */
+    public RestrictionEntry(String key, String[] selectedStrings) {
+        this.key = key;
+        this.currentValues = selectedStrings;
+    }
+
+    /**
+     * Sets the type for this restriction.
+     * @param type the type for this restriction.
+     */
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type for this restriction.
+     * @return the type for this restriction
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Returns the currently selected string value.
+     * @return the currently selected value, which can be null for types that aren't for holding
+     * single string values.
+     */
+    public String getSelectedString() {
+        return currentValue;
+    }
+
+    /**
+     * Returns the list of currently selected values.
+     * @return the list of current selections, if type is {@link #TYPE_MULTI_SELECT},
+     *  null otherwise.
+     */
+    public String[] getAllSelectedStrings() {
+        return currentValues;
+    }
+
+    /**
+     * Returns the current selected state for an entry of type {@link #TYPE_BOOLEAN}.
+     * @return the current selected state of the entry.
+     */
+    public boolean getSelectedState() {
+        return Boolean.parseBoolean(currentValue);
+    }
+
+    /**
+     * Sets the string value to use as the selected value for this restriction. This value will
+     * be persisted by the system for later use by the application.
+     * @param selectedString the string value to select.
+     */
+    public void setSelectedString(String selectedString) {
+        currentValue = selectedString;
+    }
+
+    /**
+     * Sets the current selected state for an entry of type {@link #TYPE_BOOLEAN}. This value will
+     * be persisted by the system for later use by the application.
+     * @param state the current selected state
+     */
+    public void setSelectedState(boolean state) {
+        currentValue = Boolean.toString(state);
+    }
+
+    /**
+     * Sets the current list of selected values for an entry of type {@link #TYPE_MULTI_SELECT}.
+     * These values will be persisted by the system for later use by the application.
+     * @param allSelectedStrings the current list of selected values.
+     */
+    public void setAllSelectedStrings(String[] allSelectedStrings) {
+        currentValues = allSelectedStrings;
+    }
+
+    /**
+     * Sets a list of string values that can be selected by the user. If no user-visible entries
+     * are set by a call to {@link #setChoiceEntries(String[])}, these values will be the ones
+     * shown to the user. Values will be chosen from this list as the user's selection and the
+     * selected values can be retrieved by a call to {@link #getAllSelectedStrings()}, or
+     * {@link #getSelectedString()}, depending on whether it is a multi-select type or choice type.
+     * This method is not relevant for types other than {@link #TYPE_CHOICE_LEVEL},
+     * {@link #TYPE_CHOICE}, and {@link #TYPE_MULTI_SELECT}.
+     * @param choiceValues an array of Strings which will be the selected values for the user's
+     * selections.
+     * @see #getChoiceValues()
+     * @see #getAllSelectedStrings()
+     */
+    public void setChoiceValues(String[] choiceValues) {
+        values = choiceValues;
+    }
+
+    /**
+     * Sets a list of string values that can be selected by the user, similar to
+     * {@link #setChoiceValues(String[])}.
+     * @param context the application context for retrieving the resources.
+     * @param stringArrayResId the resource id for a string array containing the possible values.
+     * @see #setChoiceValues(String[])
+     */
+    public void setChoiceValues(Context context, int stringArrayResId) {
+        values = context.getResources().getStringArray(stringArrayResId);
+    }
+
+    /**
+     * Returns the list of possible string values set earlier.
+     * @return the list of possible values.
+     */
+    public String[] getChoiceValues() {
+        return values;
+    }
+
+    /**
+     * Sets a list of strings that will be presented as choices to the user. When the
+     * user selects one or more of these choices, the corresponding value from the possible values
+     * are stored as the selected strings. The size of this array must match the size of the array
+     * set in {@link #setChoiceValues(String[])}. This method is not relevant for types other
+     * than {@link #TYPE_CHOICE_LEVEL}, {@link #TYPE_CHOICE}, and {@link #TYPE_MULTI_SELECT}.
+     * @param choiceEntries the list of user-visible choices.
+     * @see #setChoiceValues(String[])
+     */
+    public void setChoiceEntries(String[] choiceEntries) {
+        choices = choiceEntries;
+    }
+
+    /** Sets a list of strings that will be presented as choices to the user. This is similar to
+     * {@link #setChoiceEntries(String[])}.
+     * @param context the application context, used for retrieving the resources.
+     * @param stringArrayResId the resource id of a string array containing the possible entries.
+     */
+    public void setChoiceEntries(Context context, int stringArrayResId) {
+        choices = context.getResources().getStringArray(stringArrayResId);
+    }
+
+    /**
+     * Returns the list of strings, set earlier, that will be presented as choices to the user.
+     * @return the list of choices presented to the user.
+     */
+    public String[] getChoiceEntries() {
+        return choices;
+    }
+
+    /**
+     * Returns the provided user-visible description of the entry, if any.
+     * @return the user-visible description, null if none was set earlier.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Sets the user-visible description of the entry, as a possible sub-text for the title.
+     * You can use this to describe the entry in more detail or to display the current state of
+     * the restriction.
+     * @param description the user-visible description string.
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * This is the unique key for the restriction entry.
+     * @return the key for the restriction.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Returns the user-visible title for the entry, if any.
+     * @return the user-visible title for the entry, null if none was set earlier.
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * Sets the user-visible title for the entry.
+     * @param title the user-visible title for the entry.
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    private boolean equalArrays(String[] one, String[] other) {
+        if (one.length != other.length) return false;
+        for (int i = 0; i < one.length; i++) {
+            if (!one[i].equals(other[i])) return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) return true;
+        if (!(o instanceof RestrictionEntry)) return false;
+        final RestrictionEntry other = (RestrictionEntry) o;
+        // Make sure that either currentValue matches or currentValues matches.
+        return type == other.type && key.equals(other.key)
+                &&
+                ((currentValues == null && other.currentValues == null
+                  && currentValue != null && currentValue.equals(other.currentValue))
+                 ||
+                 (currentValue == null && other.currentValue == null
+                  && currentValues != null && equalArrays(currentValues, other.currentValues)));
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + key.hashCode();
+        if (currentValue != null) {
+            result = 31 * result + currentValue.hashCode();
+        } else if (currentValues != null) {
+            for (String value : currentValues) {
+                if (value != null) {
+                    result = 31 * result + value.hashCode();
+                }
+            }
+        }
+        return result;
+    }
+
+    private String[] readArray(Parcel in) {
+        int count = in.readInt();
+        String[] values = new String[count];
+        for (int i = 0; i < count; i++) {
+            values[i] = in.readString();
+        }
+        return values;
+    }
+
+    public RestrictionEntry(Parcel in) {
+        type = in.readInt();
+        key = in.readString();
+        title = in.readString();
+        description = in.readString();
+        choices = readArray(in);
+        values = readArray(in);
+        currentValue = in.readString();
+        currentValues = readArray(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private void writeArray(Parcel dest, String[] values) {
+        if (values == null) {
+            dest.writeInt(0);
+        } else {
+            dest.writeInt(values.length);
+            for (int i = 0; i < values.length; i++) {
+                dest.writeString(values[i]);
+            }
+        }
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(type);
+        dest.writeString(key);
+        dest.writeString(title);
+        dest.writeString(description);
+        writeArray(dest, choices);
+        writeArray(dest, values);
+        dest.writeString(currentValue);
+        writeArray(dest, currentValues);
+    }
+
+    public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() {
+        public RestrictionEntry createFromParcel(Parcel source) {
+            return new RestrictionEntry(source);
+        }
+
+        public RestrictionEntry[] newArray(int size) {
+            return new RestrictionEntry[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return "RestrictionsEntry {type=" + type + ", key=" + key + ", value=" + currentValue + "}";
+    }
+}
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 841c8f4..1a8ea47 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -69,6 +69,11 @@
         sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);
     }
 </pre>
+<p>Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, paths can start
+ with a leading slash.  For example:
+<pre>
+        sURIMatcher.addURI("contacts", "/people", PEOPLE);
+</pre>
 <p>Then when you need to match against a URI, call {@link #match}, providing
 the URL that you have been given.  You can use the result to build a query,
 return a type, insert or delete a row, or whatever you need, without duplicating
@@ -143,6 +148,9 @@
      * matched. URI nodes may be exact match string, the token "*"
      * that matches any text, or the token "#" that matches only
      * numbers.
+     * <p>
+     * Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
+     * this method will accept leading slash in the path.
      *
      * @param authority the authority to match
      * @param path the path to match. * may be used as a wild card for
@@ -155,7 +163,17 @@
         if (code < 0) {
             throw new IllegalArgumentException("code " + code + " is invalid: it must be positive");
         }
-        String[] tokens = path != null ? PATH_SPLIT_PATTERN.split(path) : null;
+
+        String[] tokens = null;
+        if (path != null) {
+            String newPath = path;
+            // Strip leading slash if present.
+            if (path.length() > 0 && path.charAt(0) == '/') {
+                newPath = path.substring(1);
+            }
+            tokens = PATH_SPLIT_PATTERN.split(newPath);
+        }
+
         int numTokens = tokens != null ? tokens.length : 0;
         UriMatcher node = this;
         for (int i = -1; i < numTokens; i++) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 32cc7fd..02401dc 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -398,6 +398,15 @@
     public String[] resourceDirs;
 
     /**
+     * String retrieved from the seinfo tag found in selinux policy. This value
+     * is useful in setting an SELinux security context on the process as well
+     * as its data directory.
+     *
+     * {@hide}
+     */
+    public String seinfo;
+
+    /**
      * Paths to all shared libraries this application is linked against.  This
      * field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
      * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
@@ -477,6 +486,9 @@
         if (resourceDirs != null) {
             pw.println(prefix + "resourceDirs=" + resourceDirs);
         }
+        if (seinfo != null) {
+            pw.println(prefix + "seinfo=" + seinfo);
+        }
         pw.println(prefix + "dataDir=" + dataDir);
         if (sharedLibraryFiles != null) {
             pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles);
@@ -544,6 +556,7 @@
         publicSourceDir = orig.publicSourceDir;
         nativeLibraryDir = orig.nativeLibraryDir;
         resourceDirs = orig.resourceDirs;
+        seinfo = orig.seinfo;
         sharedLibraryFiles = orig.sharedLibraryFiles;
         dataDir = orig.dataDir;
         uid = orig.uid;
@@ -583,6 +596,7 @@
         dest.writeString(publicSourceDir);
         dest.writeString(nativeLibraryDir);
         dest.writeStringArray(resourceDirs);
+        dest.writeString(seinfo);
         dest.writeStringArray(sharedLibraryFiles);
         dest.writeString(dataDir);
         dest.writeInt(uid);
@@ -621,6 +635,7 @@
         publicSourceDir = source.readString();
         nativeLibraryDir = source.readString();
         resourceDirs = source.readStringArray();
+        seinfo = source.readString();
         sharedLibraryFiles = source.readStringArray();
         dataDir = source.readString();
         uid = source.readInt();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a32a201..a0e1555 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -239,7 +239,8 @@
     /**
      * As per {@link android.content.pm.PackageManager#setApplicationEnabledSetting}.
      */
-    void setApplicationEnabledSetting(in String packageName, in int newState, int flags, int userId);
+    void setApplicationEnabledSetting(in String packageName, in int newState, int flags,
+            int userId, String callingPackage);
     
     /**
      * As per {@link android.content.pm.PackageManager#getApplicationEnabledSetting}.
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
index 75505bc..409b5ae 100644
--- a/core/java/android/content/pm/ManifestDigest.java
+++ b/core/java/android/content/pm/ManifestDigest.java
@@ -18,10 +18,17 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Base64;
+import android.util.Slog;
 
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
-import java.util.jar.Attributes;
+
+import libcore.io.IoUtils;
 
 /**
  * Represents the manifest digest for a package. This is suitable for comparison
@@ -30,17 +37,17 @@
  * @hide
  */
 public class ManifestDigest implements Parcelable {
+    private static final String TAG = "ManifestDigest";
+
     /** The digest of the manifest in our preferred order. */
     private final byte[] mDigest;
 
-    /** Digest field names to look for in preferred order. */
-    private static final String[] DIGEST_TYPES = {
-            "SHA1-Digest", "SHA-Digest", "MD5-Digest",
-    };
-
     /** What we print out first when toString() is called. */
     private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
 
+    /** Digest algorithm to use. */
+    private static final String DIGEST_ALGORITHM = "SHA-256";
+
     ManifestDigest(byte[] digest) {
         mDigest = digest;
     }
@@ -49,26 +56,32 @@
         mDigest = source.createByteArray();
     }
 
-    static ManifestDigest fromAttributes(Attributes attributes) {
-        if (attributes == null) {
+    static ManifestDigest fromInputStream(InputStream fileIs) {
+        if (fileIs == null) {
             return null;
         }
 
-        String encodedDigest = null;
+        final MessageDigest md;
+        try {
+            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e);
+        }
 
-        for (int i = 0; i < DIGEST_TYPES.length; i++) {
-            final String value = attributes.getValue(DIGEST_TYPES[i]);
-            if (value != null) {
-                encodedDigest = value;
-                break;
+        final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md);
+        try {
+            byte[] readBuffer = new byte[8192];
+            while (dis.read(readBuffer, 0, readBuffer.length) != -1) {
+                // not using
             }
-        }
-
-        if (encodedDigest == null) {
+        } catch (IOException e) {
+            Slog.w(TAG, "Could not read manifest");
             return null;
+        } finally {
+            IoUtils.closeQuietly(dis);
         }
 
-        final byte[] digest = Base64.decode(encodedDigest, Base64.DEFAULT);
+        final byte[] digest = md.digest();
         return new ManifestDigest(digest);
     }
 
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 85f7aa5..fb539c5 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -154,7 +154,7 @@
     /**
      * Flag for {@link #requestedPermissionsFlags}: the requested permission
      * is required for the application to run; the user can not optionally
-     * disable it.  Currently all permissions are required.
+     * disable it.
      */
     public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
 
@@ -217,7 +217,13 @@
      * @hide
      */
     public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
-    
+
+    /** @hide */
+    public boolean requiredForAllUsers;
+
+    /** @hide */
+    public String restrictedAccountType;
+
     public PackageInfo() {
     }
 
@@ -258,6 +264,8 @@
         dest.writeTypedArray(configPreferences, parcelableFlags);
         dest.writeTypedArray(reqFeatures, parcelableFlags);
         dest.writeInt(installLocation);
+        dest.writeInt(requiredForAllUsers ? 1 : 0);
+        dest.writeString(restrictedAccountType);
     }
 
     public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -296,5 +304,7 @@
         configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
         reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
         installLocation = source.readInt();
+        requiredForAllUsers = source.readInt() != 0;
+        restrictedAccountType = source.readString();
     }
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c507245..da15e3b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -45,7 +45,7 @@
 
     /**
      * This exception is thrown when a given package, application, or component
-     * name can not be found.
+     * name cannot be found.
      */
     public static class NameNotFoundException extends AndroidException {
         public NameNotFoundException() {
@@ -267,7 +267,7 @@
      * user has explicitly disabled the application, regardless of what it has
      * specified in its manifest.  Because this is due to the user's request,
      * they may re-enable it if desired through the appropriate system UI.  This
-     * option currently <strong>can not</strong> be used with
+     * option currently <strong>cannot</strong> be used with
      * {@link #setComponentEnabledSetting(ComponentName, int, int)}.
      */
     public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
@@ -691,6 +691,17 @@
     public static final int DELETE_ALL_USERS = 0x00000002;
 
     /**
+     * Flag parameter for {@link #deletePackage} to indicate that, if you are calling
+     * uninstall on a system that has been updated, then don't do the normal process
+     * of uninstalling the update and rolling back to the older system version (which
+     * needs to happen for all users); instead, just mark the app as uninstalled for
+     * the current user.
+     *
+     * @hide
+     */
+    public static final int DELETE_SYSTEM_APP = 0x00000004;
+
+    /**
      * Return code for when package deletion succeeds. This is passed to the
      * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
      * succeeded in deleting the package.
@@ -1134,6 +1145,29 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports app widgets.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_APP_WIDGETS = "android.software.app_widgets";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports a home screen that is replaceable
+     * by third party applications.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports adding new input methods implemented
+     * with the {@link android.inputmethodservice.InputMethodService} API.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1230,6 +1264,23 @@
             = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
 
     /**
+     * The action used to request that the user approve a permission request
+     * from the application.
+     *
+     * @hide
+     */
+    public static final String ACTION_REQUEST_PERMISSION
+            = "android.content.pm.action.REQUEST_PERMISSION";
+
+    /**
+     * Extra field name for the list of permissions, which the user must approve.
+     *
+     * @hide
+     */
+    public static final String EXTRA_REQUEST_PERMISSION_PERMISSION_LIST
+            = "android.content.pm.extra.PERMISSION_LIST";
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      * <p>
@@ -1249,9 +1300,9 @@
      *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
      *         package is not found in the list of installed applications, the
      *         package information is retrieved from the list of uninstalled
-     *         applications(which includes installed applications as well as
-     *         applications with data directory ie applications which had been
-     *         deleted with DONT_DELTE_DATA flag set).
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      * @see #GET_ACTIVITIES
      * @see #GET_GIDS
      * @see #GET_CONFIGURATIONS
@@ -1292,7 +1343,7 @@
      * null if neither are found.
      *
      * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param packageName The name of the package to inspect.
      *
@@ -1307,7 +1358,7 @@
      * assigned to a package.
      *
      * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
      *                    desired package.
@@ -1338,7 +1389,7 @@
      * Retrieve all of the information we know about a particular permission.
      *
      * <p>Throws {@link NameNotFoundException} if a permission with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param name The fully qualified name (i.e. com.google.permission.LOGIN)
      *             of the permission you are interested in.
@@ -1374,7 +1425,7 @@
      * permissions.
      *
      * <p>Throws {@link NameNotFoundException} if a permission group with the given
-     * name can not be found on the system.
+     * name cannot be found on the system.
      *
      * @param name The fully qualified name (i.e. com.google.permission_group.APPS)
      *             of the permission you are interested in.
@@ -1403,7 +1454,7 @@
      * package/application.
      *
      * <p>Throws {@link NameNotFoundException} if an application with the given
-     * package name can not be found on the system.
+     * package name cannot be found on the system.
      *
      * @param packageName The full name (i.e. com.google.apps.contacts) of an
      *                    application.
@@ -1419,7 +1470,7 @@
      *         list of uninstalled applications(which includes
      *         installed applications as well as applications
      *         with data directory ie applications which had been
-     *         deleted with DONT_DELTE_DATA flag set).
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
      *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
@@ -1433,7 +1484,7 @@
      * class.
      *
      * <p>Throws {@link NameNotFoundException} if an activity with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity
@@ -1456,7 +1507,7 @@
      * class.
      *
      * <p>Throws {@link NameNotFoundException} if a receiver with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver
@@ -1479,7 +1530,7 @@
      * class.
      *
      * <p>Throws {@link NameNotFoundException} if a service with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service
@@ -1501,7 +1552,7 @@
      * provider class.
      *
      * <p>Throws {@link NameNotFoundException} if a provider with the given
-     * class name can not be found on the system.
+     * class name cannot be found on the system.
      *
      * @param component The full component name (i.e.
      * com.google.providers.media/com.google.providers.media.MediaProvider) of a
@@ -1538,7 +1589,7 @@
      *         installed on the device.  In the unlikely case of there being no
      *         installed packages, an empty list is returned.
      *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with DONT_DELETE_DATA
+     *         applications including those deleted with {@code DONT_DELETE_DATA}
      *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_ACTIVITIES
@@ -1608,7 +1659,7 @@
      *         installed on the device.  In the unlikely case of there being no
      *         installed packages, an empty list is returned.
      *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with DONT_DELETE_DATA
+     *         applications including those deleted with {@code DONT_DELETE_DATA}
      *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_ACTIVITIES
@@ -1701,6 +1752,29 @@
     public abstract void removePermission(String name);
 
     /**
+     * Returns an {@link Intent} suitable for passing to {@code startActivityForResult}
+     * which prompts the user to grant {@code permissions} to this application.
+     *
+     * @throws NullPointerException if {@code permissions} is {@code null}.
+     * @throws IllegalArgumentException if {@code permissions} contains {@code null}.
+     */
+    public Intent buildPermissionRequestIntent(String... permissions) {
+        if (permissions == null) {
+            throw new NullPointerException("permissions cannot be null");
+        }
+        for (String permission : permissions) {
+            if (permission == null) {
+                throw new IllegalArgumentException("permissions cannot contain null");
+            }
+        }
+
+        Intent i = new Intent(ACTION_REQUEST_PERMISSION);
+        i.putExtra(EXTRA_REQUEST_PERMISSION_PERMISSION_LIST, permissions);
+        i.setPackage("com.android.packageinstaller");
+        return i;
+    }
+
+    /**
      * Grant a permission to an application which the application does not
      * already have.  The permission must have been requested by the application,
      * but as an optional permission.  If the application is not allowed to
@@ -1813,7 +1887,7 @@
     /**
      * Return a List of all application packages that are installed on the
      * device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all
-     * applications including those deleted with DONT_DELETE_DATA (partially
+     * applications including those deleted with {@code DONT_DELETE_DATA} (partially
      * installed apps with data directory) will be returned.
      *
      * @param flags Additional option flags. Use any combination of
@@ -1824,7 +1898,7 @@
      *         is installed on the device.  In the unlikely case of there being
      *         no installed applications, an empty list is returned.
      *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
-     *         applications including those deleted with DONT_DELETE_DATA
+     *         applications including those deleted with {@code DONT_DELETE_DATA}
      *         (partially installed apps with data directory) will be returned.
      *
      * @see #GET_META_DATA
@@ -2130,7 +2204,7 @@
      * instrumentation class.
      *
      * <p>Throws {@link NameNotFoundException} if instrumentation with the
-     * given class name can not be found on the system.
+     * given class name cannot be found on the system.
      *
      * @param className The full name (i.e.
      *                  com.google.apps.contacts.InstrumentList) of an
@@ -2167,8 +2241,8 @@
      * icon.
      *
      * @param packageName The name of the package that this icon is coming from.
-     * Can not be null.
-     * @param resid The resource identifier of the desired image.  Can not be 0.
+     * Cannot be null.
+     * @param resid The resource identifier of the desired image.  Cannot be 0.
      * @param appInfo Overall information about <var>packageName</var>.  This
      * may be null, in which case the application information will be retrieved
      * for you if needed; if you already have this information around, it can
@@ -2184,7 +2258,7 @@
      * Retrieve the icon associated with an activity.  Given the full name of
      * an activity, retrieves the information about it and calls
      * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its icon.
-     * If the activity can not be found, NameNotFoundException is thrown.
+     * If the activity cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose icon is to be retrieved.
      *
@@ -2203,7 +2277,7 @@
      * set, this simply returns the result of
      * getActivityIcon(intent.getClassName()).  Otherwise it resolves the intent's
      * component and returns the icon associated with the resolved component.
-     * If intent.getClassName() can not be found or the Intent can not be resolved
+     * If intent.getClassName() cannot be found or the Intent cannot be resolved
      * to a component, NameNotFoundException is thrown.
      *
      * @param intent The intent for which you would like to retrieve an icon.
@@ -2242,7 +2316,7 @@
     /**
      * Retrieve the icon associated with an application.  Given the name of the
      * application's package, retrieves the information about it and calls
-     * getApplicationIcon() to return its icon. If the application can not be
+     * getApplicationIcon() to return its icon. If the application cannot be
      * found, NameNotFoundException is thrown.
      *
      * @param packageName Name of the package whose application icon is to be
@@ -2262,7 +2336,7 @@
      * Retrieve the logo associated with an activity.  Given the full name of
      * an activity, retrieves the information about it and calls
      * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo.
-     * If the activity can not be found, NameNotFoundException is thrown.
+     * If the activity cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose logo is to be retrieved.
      *
@@ -2282,7 +2356,7 @@
      * set, this simply returns the result of
      * getActivityLogo(intent.getClassName()).  Otherwise it resolves the intent's
      * component and returns the logo associated with the resolved component.
-     * If intent.getClassName() can not be found or the Intent can not be resolved
+     * If intent.getClassName() cannot be found or the Intent cannot be resolved
      * to a component, NameNotFoundException is thrown.
      *
      * @param intent The intent for which you would like to retrieve a logo.
@@ -2314,7 +2388,7 @@
     /**
      * Retrieve the logo associated with an application.  Given the name of the
      * application's package, retrieves the information about it and calls
-     * getApplicationLogo() to return its logo. If the application can not be
+     * getApplicationLogo() to return its logo. If the application cannot be
      * found, NameNotFoundException is thrown.
      *
      * @param packageName Name of the package whose application logo is to be
@@ -2338,8 +2412,8 @@
      * labels and other text.
      *
      * @param packageName The name of the package that this text is coming from.
-     * Can not be null.
-     * @param resid The resource identifier of the desired text.  Can not be 0.
+     * Cannot be null.
+     * @param resid The resource identifier of the desired text.  Cannot be 0.
      * @param appInfo Overall information about <var>packageName</var>.  This
      * may be null, in which case the application information will be retrieved
      * for you if needed; if you already have this information around, it can
@@ -2356,8 +2430,8 @@
      * retrieve XML meta data.
      *
      * @param packageName The name of the package that this xml is coming from.
-     * Can not be null.
-     * @param resid The resource identifier of the desired xml.  Can not be 0.
+     * Cannot be null.
+     * @param resid The resource identifier of the desired xml.  Cannot be 0.
      * @param appInfo Overall information about <var>packageName</var>.  This
      * may be null, in which case the application information will be retrieved
      * for you if needed; if you already have this information around, it can
@@ -2375,7 +2449,7 @@
      *
      * @return Returns the label associated with this application, or null if
      * it could not be found for any reason.
-     * @param info The application to get the label of
+     * @param info The application to get the label of.
      */
     public abstract CharSequence getApplicationLabel(ApplicationInfo info);
 
@@ -2383,7 +2457,7 @@
      * Retrieve the resources associated with an activity.  Given the full
      * name of an activity, retrieves the information about it and calls
      * getResources() to return its application's resources.  If the activity
-     * can not be found, NameNotFoundException is thrown.
+     * cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose resources are to be
      *                     retrieved.
@@ -2414,7 +2488,7 @@
      * Retrieve the resources associated with an application.  Given the full
      * package name of an application, retrieves the information about it and
      * calls getResources() to return its application's resources.  If the
-     * appPackageName can not be found, NameNotFoundException is thrown.
+     * appPackageName cannot be found, NameNotFoundException is thrown.
      *
      * @param appPackageName Package name of the application whose resources
      *                       are to be retrieved.
@@ -2583,7 +2657,7 @@
      * {@link PackageManager#VERIFICATION_REJECT}.
      *
      * @param id pending package identifier as passed via the
-     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
      * @param verificationCode either {@link PackageManager#VERIFICATION_ALLOW}
      *            or {@link PackageManager#VERIFICATION_REJECT}.
      * @throws SecurityException if the caller does not have the
@@ -2604,7 +2678,7 @@
      * will have no effect.
      *
      * @param id pending package identifier as passed via the
-     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
      * @param verificationCodeAtTimeout either
      *            {@link PackageManager#VERIFICATION_ALLOW} or
      *            {@link PackageManager#VERIFICATION_REJECT}. If
@@ -2788,16 +2862,16 @@
 
     /**
      * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superceeded
-     * (and conflicts with) the modern activity-based preferences.
+     * approach to managing preferred activities, which has been superseded
+     * by (and conflicts with) the modern activity-based preferences.
      */
     @Deprecated
     public abstract void addPackageToPreferred(String packageName);
 
     /**
      * @deprecated This function no longer does anything; it was an old
-     * approach to managing preferred activities, which has been superceeded
-     * (and conflicts with) the modern activity-based preferences.
+     * approach to managing preferred activities, which has been superseded
+     * by (and conflicts with) the modern activity-based preferences.
      */
     @Deprecated
     public abstract void removePackageFromPreferred(String packageName);
@@ -2836,7 +2910,7 @@
     /**
      * @deprecated This is a protected API that should not have been available
      * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this can not be directly modified.
+     * assigning preferred activities and this cannot be directly modified.
      *
      * Add a new preferred activity mapping to the system.  This will be used
      * to automatically select the given activity component when
@@ -2870,7 +2944,7 @@
     /**
      * @deprecated This is a protected API that should not have been available
      * to third party applications.  It is the platform's responsibility for
-     * assigning preferred activities and this can not be directly modified.
+     * assigning preferred activities and this cannot be directly modified.
      *
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e1887bc..384aed8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -24,7 +24,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PatternMatcher;
@@ -54,10 +53,9 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
-import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
 
 import com.android.internal.util.XmlUtils;
 
@@ -289,6 +287,8 @@
         pi.sharedUserLabel = p.mSharedUserLabel;
         pi.applicationInfo = generateApplicationInfo(p, flags, state, userId);
         pi.installLocation = p.installLocation;
+        pi.requiredForAllUsers = p.mRequiredForAllUsers;
+        pi.restrictedAccountType = p.mRestrictedAccountType;
         pi.firstInstallTime = firstInstallTime;
         pi.lastUpdateTime = lastUpdateTime;
         if ((flags&PackageManager.GET_GIDS) != 0) {
@@ -565,6 +565,28 @@
         return pkg;
     }
 
+    /**
+     * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
+     * APK. If it successfully scanned the package and found the
+     * {@code AndroidManifest.xml}, {@code true} is returned.
+     */
+    public boolean collectManifestDigest(Package pkg) {
+        try {
+            final JarFile jarFile = new JarFile(mArchiveSourcePath);
+            try {
+                final ZipEntry je = jarFile.getEntry(ANDROID_MANIFEST_FILENAME);
+                if (je != null) {
+                    pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
+                }
+            } finally {
+                jarFile.close();
+            }
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     public boolean collectCertificates(Package pkg, int flags) {
         pkg.mSignatures = null;
 
@@ -616,7 +638,6 @@
                 }
             } else {
                 Enumeration<JarEntry> entries = jarFile.entries();
-                final Manifest manifest = jarFile.getManifest();
                 while (entries.hasMoreElements()) {
                     final JarEntry je = entries.nextElement();
                     if (je.isDirectory()) continue;
@@ -627,8 +648,8 @@
                         continue;
 
                     if (ANDROID_MANIFEST_FILENAME.equals(name)) {
-                        final Attributes attributes = manifest.getAttributes(name);
-                        pkg.manifestDigest = ManifestDigest.fromAttributes(attributes);
+                        pkg.manifestDigest =
+                                ManifestDigest.fromInputStream(jarFile.getInputStream(je));
                     }
 
                     final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer);
@@ -1015,27 +1036,10 @@
                     return null;
                 }
             } else if (tagName.equals("uses-permission")) {
-                sa = res.obtainAttributes(attrs,
-                        com.android.internal.R.styleable.AndroidManifestUsesPermission);
-
-                // Note: don't allow this value to be a reference to a resource
-                // that may change.
-                String name = sa.getNonResourceString(
-                        com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
-                /* Not supporting optional permissions yet.
-                boolean required = sa.getBoolean(
-                        com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
-                */
-
-                sa.recycle();
-
-                if (name != null && !pkg.requestedPermissions.contains(name)) {
-                    pkg.requestedPermissions.add(name.intern());
-                    pkg.requestedPermissionsRequired.add(Boolean.TRUE);
+                if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
+                    return null;
                 }
 
-                XmlUtils.skipCurrentTag(parser);
-
             } else if (tagName.equals("uses-configuration")) {
                 ConfigurationInfo cPref = new ConfigurationInfo();
                 sa = res.obtainAttributes(attrs,
@@ -1379,9 +1383,53 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
         }
 
+        /*
+         * b/8528162: Ignore the <uses-permission android:required> attribute if
+         * targetSdkVersion < JELLY_BEAN_MR2. There are lots of apps in the wild
+         * which are improperly using this attribute, even though it never worked.
+         */
+        if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            for (int i = 0; i < pkg.requestedPermissionsRequired.size(); i++) {
+                pkg.requestedPermissionsRequired.set(i, Boolean.TRUE);
+            }
+        }
+
         return pkg;
     }
 
+    private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser,
+                                        AttributeSet attrs, String[] outError)
+            throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(attrs,
+                com.android.internal.R.styleable.AndroidManifestUsesPermission);
+
+        // Note: don't allow this value to be a reference to a resource
+        // that may change.
+        String name = sa.getNonResourceString(
+                com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
+        boolean required = sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestUsesPermission_required, true);
+
+        sa.recycle();
+
+        if (name != null) {
+            int index = pkg.requestedPermissions.indexOf(name);
+            if (index == -1) {
+                pkg.requestedPermissions.add(name.intern());
+                pkg.requestedPermissionsRequired.add(required ? Boolean.TRUE : Boolean.FALSE);
+            } else {
+                if (pkg.requestedPermissionsRequired.get(index) != required) {
+                    outError[0] = "conflicting <uses-permission> entries";
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                    return false;
+                }
+            }
+        }
+
+        XmlUtils.skipCurrentTag(parser);
+        return true;
+    }
+
     private static String buildClassName(String pkg, CharSequence clsSeq,
             String[] outError) {
         if (clsSeq == null || clsSeq.length() <= 0) {
@@ -1760,6 +1808,16 @@
                     false)) {
                 ai.flags |= ApplicationInfo.FLAG_PERSISTENT;
             }
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestApplication_requiredForAllUsers,
+                    false)) {
+                owner.mRequiredForAllUsers = true;
+            }
+            String accountType = sa.getString(com.android.internal.R.styleable
+                    .AndroidManifestApplication_restrictedAccountType);
+            if (accountType != null && accountType.length() > 0) {
+                owner.mRestrictedAccountType = accountType;
+            }
         }
 
         if (sa.getBoolean(
@@ -1941,6 +1999,28 @@
                     return false;
                 }
 
+            } else if (tagName.equals("library")) {
+                sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.AndroidManifestLibrary);
+
+                // Note: don't allow this value to be a reference to a resource
+                // that may change.
+                String lname = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestLibrary_name);
+
+                sa.recycle();
+
+                if (lname != null) {
+                    if (owner.libraryNames == null) {
+                        owner.libraryNames = new ArrayList<String>();
+                    }
+                    if (!owner.libraryNames.contains(lname)) {
+                        owner.libraryNames.add(lname.intern());
+                    }
+                }
+
+                XmlUtils.skipCurrentTag(parser);
+
             } else if (tagName.equals("uses-library")) {
                 sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
@@ -3165,6 +3245,7 @@
     }
 
     public final static class Package {
+
         public String packageName;
 
         // For now we only support one application per package.
@@ -3182,7 +3263,8 @@
         public final ArrayList<Boolean> requestedPermissionsRequired = new ArrayList<Boolean>();
 
         public ArrayList<String> protectedBroadcasts;
-        
+
+        public ArrayList<String> libraryNames = null;
         public ArrayList<String> usesLibraries = null;
         public ArrayList<String> usesOptionalLibraries = null;
         public String[] usesLibraryFiles = null;
@@ -3248,6 +3330,12 @@
 
         public int installLocation;
 
+        /* An app that's required for all users and cannot be uninstalled for a user */
+        public boolean mRequiredForAllUsers;
+
+        /* The restricted account authenticator type that is used by this application */
+        public String mRestrictedAccountType;
+
         /**
          * Digest suitable for comparing whether this package's manifest is the
          * same as another.
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 3579977..dcd54fc 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -30,6 +30,8 @@
     public boolean installed;
     public int enabled;
 
+    public String lastDisableAppCaller;
+
     public HashSet<String> disabledComponents;
     public HashSet<String> enabledComponents;
 
@@ -43,6 +45,7 @@
         stopped = o.stopped;
         notLaunched = o.notLaunched;
         enabled = o.enabled;
+        lastDisableAppCaller = o.lastDisableAppCaller;
         disabledComponents = o.disabledComponents != null
                 ? new HashSet<String>(o.disabledComponents) : null;
         enabledComponents = o.enabledComponents != null
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index aaa0917..288d55f 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -488,7 +488,8 @@
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
             int eventType = parser.getEventType();
-            while (eventType != XmlPullParser.START_TAG) {
+            while (eventType != XmlPullParser.START_TAG
+                    && eventType != XmlPullParser.END_DOCUMENT) {
                 eventType = parser.next();
             }
             String tagName = parser.getName();
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 24a0bb5..0152615 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -233,11 +233,13 @@
     }
 
     /**
-     * Return the character sequence associated with a particular resource ID for a particular
-     * numerical quantity.
-     *
-     * <p>See <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String
-     * Resources</a> for more on quantity strings.
+     * Returns the character sequence necessary for grammatically correct pluralization
+     * of the given resource ID for the given quantity.
+     * Note that the character sequence is selected based solely on grammatical necessity,
+     * and that such rules differ between languages. Do not assume you know which string
+     * will be returned for a given quantity. See
+     * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
+     * for more detail.
      *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
@@ -345,14 +347,17 @@
     }
 
     /**
-     * Return the string value associated with a particular resource ID for a particular
-     * numerical quantity, substituting the format arguments as defined in
-     * {@link java.util.Formatter} and {@link java.lang.String#format}. It will be
-     * stripped of any styled text information.
-     * {@more}
+     * Formats the string necessary for grammatically correct pluralization
+     * of the given resource ID for the given quantity, using the given arguments.
+     * Note that the string is selected based solely on grammatical necessity,
+     * and that such rules differ between languages. Do not assume you know which string
+     * will be returned for a given quantity. See
+     * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
+     * for more detail.
      *
-     * <p>See <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String
-     * Resources</a> for more on quantity strings.
+     * <p>Substitution of format arguments works as if using
+     * {@link java.util.Formatter} and {@link java.lang.String#format}.
+     * The resulting string will be stripped of any styled text information.
      *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
@@ -373,11 +378,13 @@
     }
 
     /**
-     * Return the string value associated with a particular resource ID for a particular
-     * numerical quantity.
-     *
-     * <p>See <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String
-     * Resources</a> for more on quantity strings.
+     * Returns the string necessary for grammatically correct pluralization
+     * of the given resource ID for the given quantity.
+     * Note that the string is selected based solely on grammatical necessity,
+     * and that such rules differ between languages. Do not assume you know which string
+     * will be returned for a given quantity. See
+     * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
+     * for more detail.
      *
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
@@ -1732,6 +1739,15 @@
     }
 
     /**
+     * Return true if given resource identifier includes a package.
+     *
+     * @hide
+     */
+    public static boolean resourceHasPackage(int resid) {
+        return (resid >>> 24) != 0;
+    }
+
+    /**
      * Return the full name for a given resource identifier.  This name is
      * a single string of the form "package:type/entry".
      * 
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index c0d2fae..7f94794 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -572,7 +572,10 @@
      *        are received faster. The value must be one of
      *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}
-     *        or, the desired delay between events in microsecond.
+     *        or, the desired delay between events in microseconds.
+     *        Specifying the delay in microseconds only works from Android
+     *        2.3 (API level 9) onwards. For earlier releases, you must use
+     *        one of the {@code SENSOR_DELAY_*} constants.
      *
      * @return <code>true</code> if the sensor is supported and successfully
      *         enabled.
@@ -604,7 +607,10 @@
      *        are received faster. The value must be one of
      *        {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
      *        {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
-     *        or, the desired delay between events in microsecond.
+     *        or, the desired delay between events in microseconds.
+     *        Specifying the delay in microseconds only works from Android
+     *        2.3 (API level 9) onwards. For earlier releases, you must use
+     *        one of the {@code SENSOR_DELAY_*} constants.
      *
      * @param handler
      *        The {@link android.os.Handler Handler} the
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
new file mode 100644
index 0000000..35bbb9c
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -0,0 +1,439 @@
+/*
+ * 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.content.Context;
+import android.location.Location;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * This class handles geofences managed by various hardware subsystems. It contains
+ * the public APIs that is needed to accomplish the task.
+ *
+ * <p>The APIs should not be called directly by the app developers. A higher level api
+ * 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.
+ *
+ * <p> There are 3 states associated with a Geofence: Inside, Outside, Unknown.
+ * There are 3 transitions: {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED},
+ * {@link #GEOFENCE_UNCERTAIN}. The APIs only expose the transitions.
+ *
+ * <p> Inside state: The hardware subsystem is reasonably confident that the user is inside
+ * the geofence. Outside state: The hardware subsystem is reasonably confident that the user
+ * is outside the geofence Unknown state: Unknown state can be interpreted as a state in which the
+ * monitoring subsystem isn't confident enough that the user is either inside or
+ * outside the Geofence. If the accuracy does not improve for a sufficient period of time,
+ * the {@link #GEOFENCE_UNCERTAIN} transition would be triggered. If the accuracy improves later,
+ * an appropriate transition would be triggered. The "reasonably confident" parameter
+ * depends on the hardware system and the positioning algorithms used.
+ * For instance, {@link #MONITORING_TYPE_GPS_HARDWARE} uses 95% as a confidence level.
+ */
+public final class GeofenceHardware {
+    private IGeofenceHardware mService;
+
+    // Hardware systems that do geofence monitoring.
+    static final int NUM_MONITORS = 1;
+
+    /**
+     * Constant for geofence monitoring done by the GPS hardware.
+     */
+    public static final int MONITORING_TYPE_GPS_HARDWARE = 0;
+
+    /**
+     * Constant to indiciate that the monitoring system is currently
+     * available for monitoring geofences.
+     */
+    public static final int MONITOR_CURRENTLY_AVAILABLE = 0;
+
+    /**
+     * Constant to indiciate that the monitoring system is currently
+     * unavailable for monitoring geofences.
+     */
+    public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1;
+
+    /**
+     * Constant to indiciate that the monitoring system is unsupported
+     * for hardware geofence monitoring.
+     */
+    public static final int MONITOR_UNSUPPORTED = 2;
+
+    // The following constants need to match geofence flags in gps.h
+    /**
+     * The constant to indicate that the user has entered the geofence.
+     */
+    public static final int GEOFENCE_ENTERED = 1<<0L;
+
+    /**
+     * The constant to indicate that the user has exited the geofence.
+     */
+    public static final int GEOFENCE_EXITED = 1<<1L;
+
+    /**
+     * The constant to indicate that the user is uncertain with respect to a
+     * geofence.                                                  nn
+     */
+    public static final int GEOFENCE_UNCERTAIN = 1<<2L;
+
+    /**
+     * The constant used to indicate success of the particular geofence call
+     */
+    public static final int GEOFENCE_SUCCESS = 0;
+
+    /**
+     * The constant used to indicate that too many geofences have been registered.
+     */
+    public static final int GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 1;
+
+    /**
+     * The constant used to indicate that the geofence id already exists.
+     */
+    public static final int GEOFENCE_ERROR_ID_EXISTS  = 2;
+
+    /**
+     * The constant used to indicate that the geofence id is unknown.
+     */
+    public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3;
+
+    /**
+     * The constant used to indicate that the transition requested for the geofence is invalid.
+     */
+    public static final int GEOFENCE_ERROR_INVALID_TRANSITION = 4;
+
+    /**
+     * The constant used to indicate that the geofence operation has failed.
+     */
+    public static final int GEOFENCE_FAILURE = 5;
+
+    static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
+    static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
+
+    private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
+            mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
+    /**
+     * @hide
+     */
+    public GeofenceHardware(IGeofenceHardware service) {
+        mService = service;
+    }
+
+    /**
+     * Returns all the hardware geofence monitoring systems and their status.
+     * 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
+     * for monitoring geofences in certain scenarios. For example, when a user
+     * enters a building, the GPS hardware subsystem might not be able monitor
+     * 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.
+     */
+    public int[] getMonitoringTypesAndStatus() {
+        try {
+            return mService.getMonitoringTypesAndStatus();
+        } catch (RemoteException e) {
+        }
+        return new int[0];
+    }
+
+    /**
+     * Creates a circular geofence which is monitored by subsystems in the hardware.
+     *
+     * <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
+     * <ul>
+     * <li> The geofence Id
+     * <li> The location object indicating the last known location.
+     * <li> The transition associated with the geofence. One of
+     *      {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
+     * <li> The timestamp when the geofence transition occured.
+     * <li> The monitoring type ({@link #MONITORING_TYPE_GPS_HARDWARE} is one such example)
+     *      that was used.
+     * </ul>
+     *
+     * <p> The geofence will be monitored by the subsystem specified by monitoring_type parameter.
+     * The application does not need to hold a wakelock when the monitoring
+     * is being done by the underlying hardware subsystem. If the same geofence Id is being
+     * monitored by two different monitoring systems, the same id can be used for both calls, as
+     * long as the same callback object is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
+     * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * <p>This API should not be called directly by the app developers. A higher level api
+     * 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.
+     * @param monitoringType The type of the hardware subsystem that should be used
+     *        to monitor the geofence.
+     * @param callback {@link GeofenceHardwareCallback} that will be use to notify the
+     *        transition.
+     * @return true on success.
+     */
+    public boolean addCircularFence(int geofenceId, double latitude, double longitude,
+            double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
+            int unknownTimer, int monitoringType, GeofenceHardwareCallback callback) {
+        try {
+            return mService.addCircularFence(geofenceId, latitude, longitude, radius,
+                    lastTransition, monitorTransitions, notificationResponsivenes, unknownTimer,
+                    monitoringType, getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Removes a geofence added by {@link #addCircularFence} call.
+     *
+     * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
+     * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * <p>This API should not be called directly by the app developers. A higher level api
+     * 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 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.
+     */
+   public boolean removeGeofence(int geofenceId, int monitoringType) {
+       try {
+           return mService.removeGeofence(geofenceId, monitoringType);
+       } catch (RemoteException e) {
+       }
+       return false;
+   }
+
+    /**
+     * Pauses the monitoring of a geofence added by {@link #addCircularFence} call.
+     *
+     * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
+     * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * <p>This API should not be called directly by the app developers. A higher level api
+     * 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 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.
+     */
+    public boolean pauseGeofence(int geofenceId, int monitoringType) {
+        try {
+            return mService.pauseGeofence(geofenceId, monitoringType);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Resumes the monitoring of a geofence added by {@link #pauseGeofence} call.
+     *
+     * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
+     * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * <p>This API should not be called directly by the app developers. A higher level api
+     * 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 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.
+     */
+    public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+        try {
+            return mService.resumeGeofence(geofenceId, monitorTransition, monitoringType);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Register the callback to be notified when the state of a hardware geofence
+     * monitoring system changes. For instance, it can change from
+     * {@link #MONITOR_CURRENTLY_AVAILABLE} to {@link #MONITOR_CURRENTLY_UNAVAILABLE}
+     *
+     * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
+     * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * <p>This API should not be called directly by the app developers. A higher level api
+     * 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.
+     *
+     * <p> The same callback object can be used to be informed of geofence transitions
+     * and state changes of the underlying hardware subsystem.
+     *
+     * @param monitoringType Type of the monitor
+     * @param callback Callback that will be called.
+     * @return true on success
+     */
+    public boolean registerForMonitorStateChangeCallback(int monitoringType,
+            GeofenceHardwareCallback callback) {
+        try {
+            return mService.registerForMonitorStateChangeCallback(monitoringType,
+                    getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Unregister the callback that was used with {@link #registerForMonitorStateChangeCallback}
+     * to notify when the state of the hardware geofence monitoring system changes.
+     *
+     * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
+     * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * <p>This API should not be called directly by the app developers. A higher level api
+     * 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 monitoringType Type of the monitor
+     * @param callback Callback that will be called.
+     * @return true on success
+     */
+    public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
+            GeofenceHardwareCallback callback) {
+        boolean  result = false;
+        try {
+            result = mService.unregisterForMonitorStateChangeCallback(monitoringType,
+                    getCallbackWrapper(callback));
+            if (result) removeCallback(callback);
+
+        } catch (RemoteException e) {
+        }
+        return result;
+    }
+
+
+    private void removeCallback(GeofenceHardwareCallback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+        }
+    }
+
+    private GeofenceHardwareCallbackWrapper getCallbackWrapper(GeofenceHardwareCallback callback) {
+        synchronized (mCallbacks) {
+            GeofenceHardwareCallbackWrapper wrapper = mCallbacks.get(callback);
+            if (wrapper == null) {
+                wrapper = new GeofenceHardwareCallbackWrapper(callback);
+                mCallbacks.put(callback, wrapper);
+            }
+            return wrapper;
+        }
+    }
+
+    class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
+        private WeakReference<GeofenceHardwareCallback> mCallback;
+
+        GeofenceHardwareCallbackWrapper(GeofenceHardwareCallback c) {
+            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,
+                long timestamp, int monitoringType) {
+            GeofenceHardwareCallback c = mCallback.get();
+            if (c != null) {
+                c.onGeofenceChange(geofenceId, transition, location, timestamp,
+                        monitoringType);
+            }
+        }
+
+        public void onGeofenceAdd(int geofenceId, int status) {
+            GeofenceHardwareCallback c = mCallback.get();
+            if (c != null) c.onGeofenceAdd(geofenceId, status);
+        }
+
+        public void onGeofenceRemove(int geofenceId, int status) {
+            GeofenceHardwareCallback c = mCallback.get();
+            if (c != null) {
+                c.onGeofenceRemove(geofenceId, status);
+                removeCallback(c);
+            }
+        }
+
+        public void onGeofencePause(int geofenceId, int status) {
+            GeofenceHardwareCallback c = mCallback.get();
+            if (c != null) c.onGeofencePause(geofenceId, status);
+        }
+
+        public void onGeofenceResume(int geofenceId, int status) {
+            GeofenceHardwareCallback c = mCallback.get();
+            if (c != null) c.onGeofenceResume(geofenceId, status);
+        }
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java
new file mode 100644
index 0000000..8ab582a
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java
@@ -0,0 +1,100 @@
+/*
+ * 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 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.
+     *
+     * @param geofenceId The geofence ID of the geofence
+     * @param transition One of {@link GeofenceHardware#GEOFENCE_ENTERED},
+     *        {@link GeofenceHardware#GEOFENCE_EXITED}, {@link GeofenceHardware#GEOFENCE_UNCERTAIN}
+     * @param location The last known location according to the monitoring system.
+     * @param timestamp The timestamp (elapsed real time in milliseconds) when the transition was
+     *        detected
+     * @param monitoringType Type of the monitoring system.
+     */
+    public void onGeofenceChange(int geofenceId, int transition, Location location,
+            long timestamp, int monitoringType) {
+    }
+
+    /**
+     * The callback called to notify the success or failure of the add call.
+     *
+     * @param geofenceId The ID of the geofence.
+     * @param status One of {@link GeofenceHardware#GEOFENCE_SUCCESS},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_ID_EXISTS},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_INVALID_TRANSITION},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_TOO_MANY_GEOFENCES},
+     *        {@link GeofenceHardware#GEOFENCE_FAILURE}
+     */
+    public void onGeofenceAdd(int geofenceId, int status) {
+    }
+
+    /**
+     * The callback called to notify the success or failure of the remove call.
+     *
+     * @param geofenceId The ID of the geofence.
+     * @param status  One of {@link GeofenceHardware#GEOFENCE_SUCCESS},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_ID_UNKNOWN},
+     *        {@link GeofenceHardware#GEOFENCE_FAILURE}
+     */
+    public void onGeofenceRemove(int geofenceId, int status) {
+    }
+
+    /**
+     * The callback called to notify the success or failure of the pause call.
+     *
+     * @param geofenceId The ID of the geofence.
+     * @param status One of {@link GeofenceHardware#GEOFENCE_SUCCESS},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_ID_UNKNOWN},
+     *        {@link GeofenceHardware#GEOFENCE_FAILURE}
+     */
+    public void onGeofencePause(int geofenceId, int status) {
+    }
+
+    /**
+     * The callback called to notify the success or failure of the resume call.
+     *
+     * @param geofenceId The ID of the geofence.
+     * @param status One of {@link GeofenceHardware#GEOFENCE_SUCCESS},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_ID_UNKNOWN},
+     *        {@link GeofenceHardware#GEOFENCE_ERROR_INVALID_TRANSITION},
+     *        {@link GeofenceHardware#GEOFENCE_FAILURE}
+     */
+    public void onGeofenceResume(int geofenceId, int status) {
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
new file mode 100644
index 0000000..21f1ea6
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -0,0 +1,599 @@
+/*
+ * 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.content.Context;
+import android.content.pm.PackageManager;
+import android.location.IGpsGeofenceHardware;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This class manages the geofences which are handled by hardware.
+ *
+ * @hide
+ */
+public final class GeofenceHardwareImpl {
+    private static final String TAG = "GeofenceHardwareImpl";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private static GeofenceHardwareImpl sInstance;
+    private PowerManager.WakeLock mWakeLock;
+    private SparseArray<IGeofenceHardwareCallback> mGeofences =
+            new SparseArray<IGeofenceHardwareCallback>();
+    private ArrayList<IGeofenceHardwareCallback>[] mCallbacks =
+            new ArrayList[GeofenceHardware.NUM_MONITORS];
+
+    private IGpsGeofenceHardware mGpsService;
+
+    private int[] mSupportedMonitorTypes = new int[GeofenceHardware.NUM_MONITORS];
+
+    // mGeofenceHandler message types
+    private static final int GEOFENCE_TRANSITION_CALLBACK = 1;
+    private static final int ADD_GEOFENCE_CALLBACK = 2;
+    private static final int REMOVE_GEOFENCE_CALLBACK = 3;
+    private static final int PAUSE_GEOFENCE_CALLBACK = 4;
+    private static final int RESUME_GEOFENCE_CALLBACK = 5;
+    private static final int ADD_GEOFENCE = 6;
+    private static final int REMOVE_GEOFENCE = 7;
+
+    // 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;
+
+    // The following constants need to match GpsLocationFlags enum in gps.h
+    private static final int LOCATION_INVALID = 0;
+    private static final int LOCATION_HAS_LAT_LONG = 1;
+    private static final int LOCATION_HAS_ALTITUDE = 2;
+    private static final int LOCATION_HAS_SPEED = 4;
+    private static final int LOCATION_HAS_BEARING = 8;
+    private static final int LOCATION_HAS_ACCURACY = 16;
+
+    // Resolution level constants used for permission checks.
+    // These constants must be in increasing order of finer resolution.
+    private static final int RESOLUTION_LEVEL_NONE = 1;
+    private static final int RESOLUTION_LEVEL_COARSE = 2;
+    private static final int RESOLUTION_LEVEL_FINE = 3;
+
+    // GPS Geofence errors. Should match gps.h constants.
+    private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
+    private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
+    private static final int GPS_GEOFENCE_ERROR_ID_EXISTS  = -101;
+    private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
+    private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
+    private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
+
+
+
+    public synchronized static GeofenceHardwareImpl getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new GeofenceHardwareImpl(context);
+        }
+        return sInstance;
+    }
+
+    private GeofenceHardwareImpl(Context context) {
+        mContext = context;
+        // Init everything to unsupported.
+        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                GeofenceHardware.MONITOR_UNSUPPORTED);
+
+    }
+
+    private void acquireWakeLock() {
+        if (mWakeLock == null) {
+            PowerManager powerManager =
+                    (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+        }
+        mWakeLock.acquire();
+    }
+
+    private void releaseWakeLock() {
+        if (mWakeLock.isHeld()) mWakeLock.release();
+    }
+
+    private void updateGpsHardwareAvailability() {
+        //Check which monitors are available.
+        boolean gpsSupported;
+        try {
+            gpsSupported = mGpsService.isHardwareGeofenceSupported();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote Exception calling LocationManagerService");
+            gpsSupported = false;
+        }
+
+        if (gpsSupported) {
+            // Its assumed currently available at startup.
+            // native layer will update later.
+            setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+                    GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE);
+        }
+    }
+
+    public void setGpsHardwareGeofence(IGpsGeofenceHardware service) {
+        if (mGpsService == null) {
+            mGpsService = service;
+            updateGpsHardwareAvailability();
+        } else if (service == null) {
+            mGpsService = null;
+            Log.w(TAG, "GPS Geofence Hardware service seems to have crashed");
+        } else {
+            Log.e(TAG, "Error: GpsService being set again.");
+        }
+    }
+
+    public int[] getMonitoringTypesAndStatus() {
+        synchronized (mSupportedMonitorTypes) {
+            return mSupportedMonitorTypes;
+        }
+    }
+
+    public boolean addCircularFence(int geofenceId, double latitude, double longitude,
+            double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
+            int unknownTimer, int monitoringType, IGeofenceHardwareCallback callback) {
+        // This API is not thread safe. Operations on the same geofence need to be serialized
+        // by upper layers
+        if (DEBUG) {
+            Log.d(TAG, "addCircularFence: GeofenceId: " + geofenceId + "Latitude: " + latitude +
+                    "Longitude: " + longitude + "Radius: " + radius + "LastTransition: "
+                    + lastTransition + "MonitorTransition: " + monitorTransitions +
+                    "NotificationResponsiveness: " + notificationResponsivenes +
+                    "UnKnown Timer: " + unknownTimer + "MonitoringType: " + monitoringType);
+
+        }
+        boolean result;
+        Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE, callback);
+        m.arg1 = geofenceId;
+        mGeofenceHandler.sendMessage(m);
+
+        switch (monitoringType) {
+            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
+                if (mGpsService == null) return false;
+                try {
+                    result = mGpsService.addCircularHardwareGeofence(geofenceId, latitude,
+                            longitude, radius, lastTransition, monitorTransitions,
+                            notificationResponsivenes, unknownTimer);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "AddGeofence: Remote Exception calling LocationManagerService");
+                    result = false;
+                }
+                break;
+            default:
+                result = false;
+        }
+        if (!result) {
+            m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE);
+            m.arg1 = geofenceId;
+            mGeofenceHandler.sendMessage(m);
+        }
+
+        if (DEBUG) Log.d(TAG, "addCircularFence: Result is: " + result);
+        return result;
+    }
+
+    public boolean removeGeofence(int geofenceId, int monitoringType) {
+        // This API is not thread safe. Operations on the same geofence need to be serialized
+        // by upper layers
+        if (DEBUG) Log.d(TAG, "Remove Geofence: GeofenceId: " + geofenceId);
+        boolean result = false;
+        switch (monitoringType) {
+            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
+                if (mGpsService == null) return false;
+                try {
+                    result = mGpsService.removeHardwareGeofence(geofenceId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoveGeofence: Remote Exception calling LocationManagerService");
+                    result = false;
+                }
+                break;
+            default:
+                result = false;
+        }
+        if (DEBUG) Log.d(TAG, "removeGeofence: Result is: " + result);
+        return result;
+    }
+
+    public boolean pauseGeofence(int geofenceId, int monitoringType) {
+        // This API is not thread safe. Operations on the same geofence need to be serialized
+        // by upper layers
+        if (DEBUG) Log.d(TAG, "Pause Geofence: GeofenceId: " + geofenceId);
+        boolean result;
+        switch (monitoringType) {
+            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
+                if (mGpsService == null) return false;
+                try {
+                    result = mGpsService.pauseHardwareGeofence(geofenceId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "PauseGeofence: Remote Exception calling LocationManagerService");
+                    result = false;
+                }
+                break;
+            default:
+                result = false;
+        }
+        if (DEBUG) Log.d(TAG, "pauseGeofence: Result is: " + result);
+        return result;
+    }
+
+
+    public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+        // 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);
+        boolean result;
+        switch (monitoringType) {
+            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
+                if (mGpsService == null) return false;
+                try {
+                    result = mGpsService.resumeHardwareGeofence(geofenceId, monitorTransition);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "ResumeGeofence: Remote Exception calling LocationManagerService");
+                    result = false;
+                }
+                break;
+            default:
+                result = false;
+        }
+        if (DEBUG) Log.d(TAG, "resumeGeofence: Result is: " + result);
+        return result;
+    }
+
+    public boolean registerForMonitorStateChangeCallback(int monitoringType,
+            IGeofenceHardwareCallback callback) {
+        Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
+        m.arg1 = monitoringType;
+        mCallbacksHandler.sendMessage(m);
+        return true;
+    }
+
+    public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
+            IGeofenceHardwareCallback callback) {
+        Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
+        m.arg1 = monitoringType;
+        mCallbacksHandler.sendMessage(m);
+        return true;
+    }
+
+    private Location getLocation(int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp) {
+        if (DEBUG) Log.d(TAG, "GetLocation: " + flags + ":" + latitude);
+        Location location = new Location(LocationManager.GPS_PROVIDER);
+        if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
+            location.setLatitude(latitude);
+            location.setLongitude(longitude);
+            location.setTime(timestamp);
+            // It would be nice to push the elapsed real-time timestamp
+            // further down the stack, but this is still useful
+            location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        }
+        if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
+            location.setAltitude(altitude);
+        } else {
+            location.removeAltitude();
+        }
+        if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
+            location.setSpeed(speed);
+        } else {
+            location.removeSpeed();
+        }
+        if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
+            location.setBearing(bearing);
+        } else {
+            location.removeBearing();
+        }
+        if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
+            location.setAccuracy(accuracy);
+        } else {
+            location.removeAccuracy();
+        }
+        return location;
+    }
+
+    /**
+     * called from GpsLocationProvider to report geofence transition
+     */
+    public void reportGpsGeofenceTransition(int geofenceId, int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp, int transition, long transitionTimestamp) {
+        if (DEBUG) Log.d(TAG, "GeofenceTransition: Flags: " + flags + " Lat: " + latitude +
+            " Long: " + longitude + " Altitude: " + altitude + " Speed: " + speed + " Bearing: " +
+            bearing + " Accuracy: " + accuracy + " Timestamp: " + timestamp + " Transition: " +
+            transition + " TransitionTimestamp: " + transitionTimestamp);
+        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
+                accuracy, timestamp);
+        GeofenceTransition t = new GeofenceTransition(geofenceId, transition, timestamp, location);
+        acquireWakeLock();
+        Message m = mGeofenceHandler.obtainMessage(GEOFENCE_TRANSITION_CALLBACK, t);
+        mGeofenceHandler.sendMessage(m);
+    }
+
+    /**
+     * called from GpsLocationProvider to report GPS status change.
+     */
+    public void reportGpsGeofenceStatus(int status, int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp) {
+        Location location = getLocation(flags, latitude, longitude, altitude, speed, bearing,
+                accuracy, timestamp);
+        boolean available = false;
+        if (status == GeofenceHardware.GPS_GEOFENCE_AVAILABLE) available = true;
+
+        int val = (available ? GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE :
+                GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE);
+        setMonitorAvailability(GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, val);
+
+        acquireWakeLock();
+        Message m = mCallbacksHandler.obtainMessage(GPS_GEOFENCE_STATUS, location);
+        m.arg1 = val;
+        mCallbacksHandler.sendMessage(m);
+    }
+
+    /**
+     * called from GpsLocationProvider add geofence callback.
+     */
+    public void reportGpsGeofenceAddStatus(int geofenceId, int status) {
+        if (DEBUG) Log.d(TAG, "Add Callback: GPS : Id: " + geofenceId + " Status: " + status);
+        acquireWakeLock();
+        Message m = mGeofenceHandler.obtainMessage(ADD_GEOFENCE_CALLBACK);
+        m.arg1 = geofenceId;
+        m.arg2 = getGeofenceStatus(status);
+        mGeofenceHandler.sendMessage(m);
+    }
+
+    /**
+     * called from GpsLocationProvider remove geofence callback.
+     */
+    public void reportGpsGeofenceRemoveStatus(int geofenceId, int status) {
+        if (DEBUG) Log.d(TAG, "Remove Callback: GPS : Id: " + geofenceId + " Status: " + status);
+        acquireWakeLock();
+        Message m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE_CALLBACK);
+        m.arg1 = geofenceId;
+        m.arg2 = getGeofenceStatus(status);
+        mGeofenceHandler.sendMessage(m);
+    }
+
+    /**
+     * called from GpsLocationProvider pause geofence callback.
+     */
+    public void reportGpsGeofencePauseStatus(int geofenceId, int status) {
+        if (DEBUG) Log.d(TAG, "Pause Callback: GPS : Id: " + geofenceId + " Status: " + status);
+        acquireWakeLock();
+        Message m = mGeofenceHandler.obtainMessage(PAUSE_GEOFENCE_CALLBACK);
+        m.arg1 = geofenceId;
+        m.arg2 = getGeofenceStatus(status);
+        mGeofenceHandler.sendMessage(m);
+    }
+
+    /**
+     * called from GpsLocationProvider resume geofence callback.
+     */
+    public void reportGpsGeofenceResumeStatus(int geofenceId, int status) {
+        if (DEBUG) Log.d(TAG, "Resume Callback: GPS : Id: " + geofenceId + " Status: " + status);
+        acquireWakeLock();
+        Message m = mGeofenceHandler.obtainMessage(RESUME_GEOFENCE_CALLBACK);
+        m.arg1 = geofenceId;
+        m.arg2 = getGeofenceStatus(status);
+        mGeofenceHandler.sendMessage(m);
+    }
+
+    // All operations on mGeofences
+    private Handler mGeofenceHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            int geofenceId;
+            int status;
+            IGeofenceHardwareCallback callback;
+            switch (msg.what) {
+                case ADD_GEOFENCE:
+                    geofenceId = msg.arg1;
+                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    mGeofences.put(geofenceId, callback);
+                    break;
+                case REMOVE_GEOFENCE:
+                    geofenceId = msg.arg1;
+                    mGeofences.remove(geofenceId);
+                    break;
+                case ADD_GEOFENCE_CALLBACK:
+                    geofenceId = msg.arg1;
+                    callback = mGeofences.get(geofenceId);
+                    if (callback == null) return;
+
+                    try {
+                        callback.onGeofenceAdd(geofenceId, msg.arg2);
+                    } catch (RemoteException e) {Log.i(TAG, "Remote Exception:" + e);}
+                    releaseWakeLock();
+                    break;
+                case REMOVE_GEOFENCE_CALLBACK:
+                    geofenceId = msg.arg1;
+                    callback = mGeofences.get(geofenceId);
+                    if (callback == null) return;
+
+                    try {
+                        callback.onGeofenceRemove(geofenceId, msg.arg2);
+                    } catch (RemoteException e) {}
+                    mGeofences.remove(geofenceId);
+                    releaseWakeLock();
+                    break;
+
+                case PAUSE_GEOFENCE_CALLBACK:
+                    geofenceId = msg.arg1;
+                    callback = mGeofences.get(geofenceId);
+                    if (callback == null) return;
+
+                    try {
+                        callback.onGeofencePause(geofenceId, msg.arg2);
+                    } catch (RemoteException e) {}
+                    releaseWakeLock();
+                    break;
+
+                case RESUME_GEOFENCE_CALLBACK:
+                    geofenceId = msg.arg1;
+                    callback = mGeofences.get(geofenceId);
+                    if (callback == null) return;
+
+                    try {
+                        callback.onGeofenceResume(geofenceId, msg.arg2);
+                    } catch (RemoteException e) {}
+                    releaseWakeLock();
+                    break;
+
+                case GEOFENCE_TRANSITION_CALLBACK:
+                    GeofenceTransition geofenceTransition = (GeofenceTransition)(msg.obj);
+                    callback = mGeofences.get(geofenceTransition.mGeofenceId);
+
+                    if (DEBUG) Log.d(TAG, "GeofenceTransistionCallback: GPS : GeofenceId: " +
+                            geofenceTransition.mGeofenceId +
+                            "Transition: " + geofenceTransition.mTransition +
+                            "Location: " + geofenceTransition.mLocation + ":" + mGeofences);
+
+                    try {
+                        callback.onGeofenceChange(
+                                geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
+                                geofenceTransition.mLocation, geofenceTransition.mTimestamp,
+                                GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
+                    } catch (RemoteException e) {}
+                    releaseWakeLock();
+                    break;
+            }
+        }
+    };
+
+    // All operations on mCallbacks
+    private Handler mCallbacksHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            int monitoringType;
+            ArrayList<IGeofenceHardwareCallback> callbackList;
+            IGeofenceHardwareCallback callback;
+
+            switch (msg.what) {
+                case GPS_GEOFENCE_STATUS:
+                    Location location = (Location) msg.obj;
+                    int val = msg.arg1;
+                    boolean available;
+                    available = (val == GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE ?
+                            true : false);
+                    callbackList = mCallbacks[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE];
+                    if (callbackList == null) return;
+
+                    if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
+
+                    for (IGeofenceHardwareCallback c: callbackList) {
+                        try {
+                            c.onMonitoringSystemChange(
+                                    GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
+                                    location);
+                        } catch (RemoteException e) {}
+                    }
+                    releaseWakeLock();
+                    break;
+                case CALLBACK_ADD:
+                    monitoringType = msg.arg1;
+                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    callbackList = mCallbacks[monitoringType];
+                    if (callbackList == null) {
+                        callbackList = new ArrayList<IGeofenceHardwareCallback>();
+                        mCallbacks[monitoringType] = callbackList;
+                    }
+                    if (!callbackList.contains(callback)) callbackList.add(callback);
+                    break;
+                case CALLBACK_REMOVE:
+                    monitoringType = msg.arg1;
+                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    callbackList = mCallbacks[monitoringType];
+                    if (callbackList != null) {
+                        callbackList.remove(callback);
+                    }
+                    break;
+            }
+        }
+    };
+
+    private class GeofenceTransition {
+        private int mGeofenceId, mTransition;
+        private long mTimestamp;
+        private Location mLocation;
+
+        GeofenceTransition(int geofenceId, int transition, long timestamp, Location location) {
+            mGeofenceId = geofenceId;
+            mTransition = transition;
+            mTimestamp = timestamp;
+            mLocation = location;
+        }
+    }
+
+    private void setMonitorAvailability(int monitor, int val) {
+        synchronized (mSupportedMonitorTypes) {
+            mSupportedMonitorTypes[monitor] = val;
+        }
+    }
+
+
+    int getMonitoringResolutionLevel(int monitoringType) {
+        switch (monitoringType) {
+            case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
+                return RESOLUTION_LEVEL_FINE;
+        }
+        return RESOLUTION_LEVEL_NONE;
+    }
+
+    int getAllowedResolutionLevel(int pid, int uid) {
+        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
+                pid, uid) == PackageManager.PERMISSION_GRANTED) {
+            return RESOLUTION_LEVEL_FINE;
+        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
+                pid, uid) == PackageManager.PERMISSION_GRANTED) {
+            return RESOLUTION_LEVEL_COARSE;
+        } else {
+            return RESOLUTION_LEVEL_NONE;
+        }
+    }
+
+    private int getGeofenceStatus(int status) {
+        switch (status) {
+            case GPS_GEOFENCE_OPERATION_SUCCESS:
+                return GeofenceHardware.GEOFENCE_SUCCESS;
+            case GPS_GEOFENCE_ERROR_GENERIC:
+                return GeofenceHardware.GEOFENCE_FAILURE;
+            case GPS_GEOFENCE_ERROR_ID_EXISTS:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
+            case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
+                return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
+            case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
+                return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
+            case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
+                return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
+        }
+        return -1;
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
new file mode 100644
index 0000000..0eccee6
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -0,0 +1,134 @@
+/*
+ * 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.Manifest;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.location.IGpsGeofenceHardware;
+import android.os.Binder;
+import android.os.IBinder;
+
+/**
+ * Service that handles hardware geofencing.
+ *
+ * @hide
+ */
+public class GeofenceHardwareService extends Service {
+    private GeofenceHardwareImpl mGeofenceHardwareImpl;
+    private Context mContext;
+
+    @Override
+    public void onCreate() {
+        mContext = this;
+        mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        return false;
+    }
+
+    @Override
+    public void onDestroy() {
+        mGeofenceHardwareImpl = null;
+    }
+
+
+    private void checkPermission(int pid, int uid, int monitoringType) {
+        if (mGeofenceHardwareImpl.getAllowedResolutionLevel(pid, uid) <
+                mGeofenceHardwareImpl.getMonitoringResolutionLevel(monitoringType)) {
+            throw new SecurityException("Insufficient permissions to access hardware geofence for"
+                    + " type: " + monitoringType);
+        }
+    }
+
+    private IBinder mBinder = new IGeofenceHardware.Stub() {
+        public void setGpsGeofenceHardware(IGpsGeofenceHardware service) {
+            mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
+        }
+
+        public int[] getMonitoringTypesAndStatus() {
+            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+                    "Location Hardware permission not granted to access hardware geofence");
+
+            return mGeofenceHardwareImpl.getMonitoringTypesAndStatus();
+        }
+
+        public boolean addCircularFence(int id, double lat, double longitude, double radius,
+                int lastTransition, int monitorTransitions, int
+                notificationResponsiveness, int unknownTimer, int monitoringType,
+                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);
+        }
+
+        public boolean removeGeofence(int id, int monitoringType) {
+            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+                    "Location Hardware permission not granted to access hardware geofence");
+
+            checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
+            return mGeofenceHardwareImpl.removeGeofence(id, monitoringType);
+        }
+
+        public boolean pauseGeofence(int id, int monitoringType) {
+            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+                    "Location Hardware permission not granted to access hardware geofence");
+
+            checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
+            return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
+        }
+
+        public boolean resumeGeofence(int id, int monitorTransitions, int monitoringType) {
+            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);
+        }
+
+        public boolean registerForMonitorStateChangeCallback(int monitoringType,
+                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.registerForMonitorStateChangeCallback(monitoringType,
+                    callback);
+        }
+
+        public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
+                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.unregisterForMonitorStateChangeCallback(monitoringType,
+                    callback);
+        }
+    };
+}
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
new file mode 100644
index 0000000..4ba02b8
--- /dev/null
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -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/LICENS   E-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.IGpsGeofenceHardware;
+import android.hardware.location.IGeofenceHardwareCallback;
+
+/** @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);
+    boolean removeGeofence(int id, int monitoringType);
+    boolean pauseGeofence(int id, int monitoringType);
+    boolean resumeGeofence(int id, int monitorTransitions, int monitoringType);
+    boolean registerForMonitorStateChangeCallback(int monitoringType,
+            IGeofenceHardwareCallback callback);
+    boolean unregisterForMonitorStateChangeCallback(int monitoringType,
+            IGeofenceHardwareCallback callback);
+}
diff --git a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
new file mode 100644
index 0000000..678fc49
--- /dev/null
+++ b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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 IGeofenceHardwareCallback {
+   void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
+   void onGeofenceChange(int geofenceId, int transition, in Location location,
+            long timestamp, int monitoringType);
+   void onGeofenceAdd(int geofenceId, int status);
+   void onGeofenceRemove(int geofenceId, int status);
+   void onGeofencePause(int geofenceId, int status);
+   void onGeofenceResume(int geofenceId, int status);
+}
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index b536490..0856e27 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -17,7 +17,6 @@
 package android.hardware.usb;
 
 import android.os.ParcelFileDescriptor;
-import android.util.Log;
 
 import java.io.FileDescriptor;
 
@@ -119,10 +118,41 @@
      * @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 native_control_request(requestType, request, value, index, buffer, length, timeout);
+        return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout);
+    }
+
+    /**
+     * Performs a control transaction on endpoint zero for this device.
+     * The direction of the transfer is determined by the request type.
+     * If requestType & {@link UsbConstants#USB_ENDPOINT_DIR_MASK} is
+     * {@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.
+     *
+     * @param requestType request type for this transaction
+     * @param request request ID for this transaction
+     * @param value value field for this transaction
+     * @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 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);
+        return native_control_request(requestType, request, value, index,
+                buffer, start, length, timeout);
     }
 
     /**
@@ -130,14 +160,37 @@
      * 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 buffer buffer for data 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
+     *
+     * @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);
+    }
+
+    /**
+     * Performs a bulk transaction on the given 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 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 length, int timeout) {
-        return native_bulk_request(endpoint.getAddress(), buffer, length, timeout);
+    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);
     }
 
     /**
@@ -168,6 +221,13 @@
         return native_get_serial();
     }
 
+    private static void checkBounds(byte[] buffer, int start, int length) {
+        final int bufferLength = (buffer != null ? buffer.length : 0);
+        if (start < 0 || start + length > bufferLength) {
+            throw new IllegalArgumentException("Buffer start or length out of bounds.");
+        }
+    }
+
     private native boolean native_open(String deviceName, FileDescriptor pfd);
     private native void native_close();
     private native int native_get_fd();
@@ -175,8 +235,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 length, int timeout);
-    private native int native_bulk_request(int endpoint, byte[] buffer, int length, int timeout);
+            int index, byte[] buffer, int start, int length, int timeout);
+    private native int native_bulk_request(int endpoint, byte[] buffer,
+            int start, int length, int timeout);
     private native UsbRequest native_request_wait();
     private native String native_get_serial();
 }
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 3c3182a..3531926 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -126,11 +126,12 @@
             mRevoked = true;
             mEnabled = false;
         }
-        
+
         /**
          * Take care of dispatching incoming key events to the appropriate
          * callbacks on the service, and tell the client when this is done.
          */
+        @Override
         public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
             boolean handled = event.dispatch(AbstractInputMethodService.this,
                     mDispatcherState, this);
@@ -143,6 +144,7 @@
          * Take care of dispatching incoming trackball events to the appropriate
          * callbacks on the service, and tell the client when this is done.
          */
+        @Override
         public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) {
             boolean handled = onTrackballEvent(event);
             if (callback != null) {
@@ -154,6 +156,7 @@
          * Take care of dispatching incoming generic motion events to the appropriate
          * callbacks on the service, and tell the client when this is done.
          */
+        @Override
         public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback) {
             boolean handled = onGenericMotionEvent(event);
             if (callback != null) {
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index d78262b..726dcec 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -18,15 +18,20 @@
 
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
 
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.SparseArray;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.inputmethod.CompletionInfo;
@@ -36,14 +41,10 @@
 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
     private static final String TAG = "InputMethodWrapper";
-    private static final boolean DEBUG = false;
     
     private static final int DO_FINISH_INPUT = 60;
     private static final int DO_DISPLAY_COMPLETIONS = 65;
     private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
-    private static final int DO_DISPATCH_KEY_EVENT = 70;
-    private static final int DO_DISPATCH_TRACKBALL_EVENT = 80;
-    private static final int DO_DISPATCH_GENERIC_MOTION_EVENT = 85;
     private static final int DO_UPDATE_SELECTION = 90;
     private static final int DO_UPDATE_CURSOR = 95;
     private static final int DO_APP_PRIVATE_COMMAND = 100;
@@ -53,34 +54,30 @@
 
     HandlerCaller mCaller;
     InputMethodSession mInputMethodSession;
-    
-    // NOTE: we should have a cache of these.
-    static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
-        final IInputMethodCallback mCb;
-        InputMethodEventCallbackWrapper(IInputMethodCallback cb) {
-            mCb = cb;
-        }
-        public void finishedEvent(int seq, boolean handled) {
-            try {
-                mCb.finishedEvent(seq, handled);
-            } catch (RemoteException e) {
-            }
-        }
-    }
-    
+    InputChannel mChannel;
+    ImeInputEventReceiver mReceiver;
+
     public IInputMethodSessionWrapper(Context context,
-            InputMethodSession inputMethodSession) {
+            InputMethodSession inputMethodSession, InputChannel channel) {
         mCaller = new HandlerCaller(context, null,
                 this, true /*asyncHandler*/);
         mInputMethodSession = inputMethodSession;
+        mChannel = channel;
+        if (channel != null) {
+            mReceiver = new ImeInputEventReceiver(channel, context.getMainLooper());
+        }
     }
 
     public InputMethodSession getInternalInputMethodSession() {
         return mInputMethodSession;
     }
 
+    @Override
     public void executeMessage(Message msg) {
-        if (mInputMethodSession == null) return;
+        if (mInputMethodSession == null) {
+            // The session has been finished.
+            return;
+        }
 
         switch (msg.what) {
             case DO_FINISH_INPUT:
@@ -93,33 +90,6 @@
                 mInputMethodSession.updateExtractedText(msg.arg1,
                         (ExtractedText)msg.obj);
                 return;
-            case DO_DISPATCH_KEY_EVENT: {
-                SomeArgs args = (SomeArgs)msg.obj;
-                mInputMethodSession.dispatchKeyEvent(msg.arg1,
-                        (KeyEvent)args.arg1,
-                        new InputMethodEventCallbackWrapper(
-                                (IInputMethodCallback)args.arg2));
-                args.recycle();
-                return;
-            }
-            case DO_DISPATCH_TRACKBALL_EVENT: {
-                SomeArgs args = (SomeArgs)msg.obj;
-                mInputMethodSession.dispatchTrackballEvent(msg.arg1,
-                        (MotionEvent)args.arg1,
-                        new InputMethodEventCallbackWrapper(
-                                (IInputMethodCallback)args.arg2));
-                args.recycle();
-                return;
-            }
-            case DO_DISPATCH_GENERIC_MOTION_EVENT: {
-                SomeArgs args = (SomeArgs)msg.obj;
-                mInputMethodSession.dispatchGenericMotionEvent(msg.arg1,
-                        (MotionEvent)args.arg1,
-                        new InputMethodEventCallbackWrapper(
-                                (IInputMethodCallback)args.arg2));
-                args.recycle();
-                return;
-            }
             case DO_UPDATE_SELECTION: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 mInputMethodSession.updateSelection(args.argi1, args.argi2,
@@ -143,7 +113,7 @@
                 return;
             }
             case DO_FINISH_SESSION: {
-                mInputMethodSession = null;
+                doFinishSession();
                 return;
             }
             case DO_VIEW_CLICKED: {
@@ -153,37 +123,37 @@
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
-    
+
+    private void doFinishSession() {
+        mInputMethodSession = null;
+        if (mReceiver != null) {
+            mReceiver.dispose();
+            mReceiver = null;
+        }
+        if (mChannel != null) {
+            mChannel.dispose();
+            mChannel = null;
+        }
+    }
+
+    @Override
     public void finishInput() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_INPUT));
     }
 
+    @Override
     public void displayCompletions(CompletionInfo[] completions) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(
                 DO_DISPLAY_COMPLETIONS, completions));
     }
-    
+
+    @Override
     public void updateExtractedText(int token, ExtractedText text) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageIO(
                 DO_UPDATE_EXTRACTED_TEXT, token, text));
     }
-    
-    public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_KEY_EVENT, seq,
-                event, callback));
-    }
 
-    public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_TRACKBALL_EVENT, seq,
-                event, callback));
-    }
-
-    public void dispatchGenericMotionEvent(int seq, MotionEvent event,
-            IInputMethodCallback callback) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_GENERIC_MOTION_EVENT, seq,
-                event, callback));
-    }
-
+    @Override
     public void updateSelection(int oldSelStart, int oldSelEnd,
             int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageIIIIII(DO_UPDATE_SELECTION,
@@ -191,24 +161,74 @@
                 candidatesStart, candidatesEnd));
     }
 
+    @Override
     public void viewClicked(boolean focusChanged) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_VIEW_CLICKED, focusChanged ? 1 : 0));
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageI(DO_VIEW_CLICKED, focusChanged ? 1 : 0));
     }
 
+    @Override
     public void updateCursor(Rect newCursor) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UPDATE_CURSOR,
-                newCursor));
-    }
-    
-    public void appPrivateCommand(String action, Bundle data) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
-    }
-    
-    public void toggleSoftInput(int showFlags, int hideFlags) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageO(DO_UPDATE_CURSOR, newCursor));
     }
 
+    @Override
+    public void appPrivateCommand(String action, Bundle data) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
+    }
+
+    @Override
+    public void toggleSoftInput(int showFlags, int hideFlags) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
+    }
+
+    @Override
     public void finishSession() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
     }
+
+    private final class ImeInputEventReceiver extends InputEventReceiver
+            implements InputMethodSession.EventCallback {
+        private final SparseArray<InputEvent> mPendingEvents = new SparseArray<InputEvent>();
+
+        public ImeInputEventReceiver(InputChannel inputChannel, Looper looper) {
+            super(inputChannel, looper);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            if (mInputMethodSession == null) {
+                // The session has been finished.
+                finishInputEvent(event, false);
+                return;
+            }
+
+            final int seq = event.getSequenceNumber();
+            mPendingEvents.put(seq, event);
+            if (event instanceof KeyEvent) {
+                KeyEvent keyEvent = (KeyEvent)event;
+                mInputMethodSession.dispatchKeyEvent(seq, keyEvent, this);
+            } else {
+                MotionEvent motionEvent = (MotionEvent)event;
+                if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_TRACKBALL)) {
+                    mInputMethodSession.dispatchTrackballEvent(seq, motionEvent, this);
+                } else {
+                    mInputMethodSession.dispatchGenericMotionEvent(seq, motionEvent, this);
+                }
+            }
+        }
+
+        @Override
+        public void finishedEvent(int seq, boolean handled) {
+            int index = mPendingEvents.indexOfKey(seq);
+            if (index >= 0) {
+                InputEvent event = mPendingEvents.valueAt(index);
+                mPendingEvents.removeAt(index);
+                finishInputEvent(event, handled);
+            }
+        }
+    }
 }
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 2d67875..9306373 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -20,8 +20,8 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionCallback;
 import com.android.internal.view.InputConnectionWrapper;
 
 import android.content.Context;
@@ -32,6 +32,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.util.Log;
+import android.view.InputChannel;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputConnection;
@@ -53,8 +54,7 @@
 class IInputMethodWrapper extends IInputMethod.Stub
         implements HandlerCaller.Callback {
     private static final String TAG = "InputMethodWrapper";
-    private static final boolean DEBUG = false;
-    
+
     private static final int DO_DUMP = 1;
     private static final int DO_ATTACH_TOKEN = 10;
     private static final int DO_SET_INPUT_CONTEXT = 20;
@@ -78,20 +78,29 @@
     }
     
     // NOTE: we should have a cache of these.
-    static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
+    static final class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
         final Context mContext;
-        final IInputMethodCallback mCb;
-        InputMethodSessionCallbackWrapper(Context context, IInputMethodCallback cb) {
+        final InputChannel mChannel;
+        final IInputSessionCallback mCb;
+
+        InputMethodSessionCallbackWrapper(Context context, InputChannel channel,
+                IInputSessionCallback cb) {
             mContext = context;
+            mChannel = channel;
             mCb = cb;
         }
+
+        @Override
         public void sessionCreated(InputMethodSession session) {
             try {
                 if (session != null) {
                     IInputMethodSessionWrapper wrap =
-                            new IInputMethodSessionWrapper(mContext, session);
+                            new IInputMethodSessionWrapper(mContext, session, mChannel);
                     mCb.sessionCreated(wrap);
                 } else {
+                    if (mChannel != null) {
+                        mChannel.dispose();
+                    }
                     mCb.sessionCreated(null);
                 }
             } catch (RemoteException e) {
@@ -112,6 +121,7 @@
         return mInputMethod.get();
     }
 
+    @Override
     public void executeMessage(Message msg) {
         InputMethod inputMethod = mInputMethod.get();
         // Need a valid reference to the inputMethod for everything except a dump.
@@ -174,8 +184,11 @@
                 return;
             }
             case DO_CREATE_SESSION: {
+                SomeArgs args = (SomeArgs)msg.obj;
                 inputMethod.createSession(new InputMethodSessionCallbackWrapper(
-                        mCaller.mContext, (IInputMethodCallback)msg.obj));
+                        mCaller.mContext, (InputChannel)args.arg1,
+                        (IInputSessionCallback)args.arg2));
+                args.recycle();
                 return;
             }
             case DO_SET_SESSION_ENABLED:
@@ -197,8 +210,9 @@
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
-    
-    @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         AbstractInputMethodService target = mTarget.get();
         if (target == null) {
             return;
@@ -224,10 +238,12 @@
         }
     }
 
+    @Override
     public void attachToken(IBinder token) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token));
     }
-    
+
+    @Override
     public void bindInput(InputBinding binding) {
         InputConnection ic = new InputConnectionWrapper(
                 IInputContext.Stub.asInterface(binding.getConnectionToken()));
@@ -235,24 +251,30 @@
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
     }
 
+    @Override
     public void unbindInput() {
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT));
     }
 
+    @Override
     public void startInput(IInputContext inputContext, EditorInfo attribute) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_START_INPUT,
                 inputContext, attribute));
     }
 
+    @Override
     public void restartInput(IInputContext inputContext, EditorInfo attribute) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_RESTART_INPUT,
                 inputContext, attribute));
     }
 
-    public void createSession(IInputMethodCallback callback) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CREATE_SESSION, callback));
+    @Override
+    public void createSession(InputChannel channel, IInputSessionCallback callback) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_SESSION,
+                channel, callback));
     }
 
+    @Override
     public void setSessionEnabled(IInputMethodSession session, boolean enabled) {
         try {
             InputMethodSession ls = ((IInputMethodSessionWrapper)
@@ -263,7 +285,8 @@
             Log.w(TAG, "Incoming session not of correct type: " + session, e);
         }
     }
-    
+
+    @Override
     public void revokeSession(IInputMethodSession session) {
         try {
             InputMethodSession ls = ((IInputMethodSessionWrapper)
@@ -273,17 +296,20 @@
             Log.w(TAG, "Incoming session not of correct type: " + session, e);
         }
     }
-    
+
+    @Override
     public void showSoftInput(int flags, ResultReceiver resultReceiver) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_SHOW_SOFT_INPUT,
                 flags, resultReceiver));
     }
-    
+
+    @Override
     public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT,
                 flags, resultReceiver));
     }
 
+    @Override
     public void changeInputMethodSubtype(InputMethodSubtype subtype) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_CHANGE_INPUTMETHOD_SUBTYPE,
                 subtype));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 99624cc..2b15afd 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -48,6 +48,7 @@
 import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
+import android.view.WindowManager.BadTokenException;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.EditorInfo;
@@ -421,7 +422,13 @@
             boolean wasVis = isInputViewShown();
             mShowInputFlags = 0;
             if (onShowInputRequested(flags, false)) {
-                showWindow(true);
+                try {
+                    showWindow(true);
+                } catch (BadTokenException e) {
+                    if (DEBUG) Log.v(TAG, "BadTokenException: IME is done.");
+                    mWindowVisible = false;
+                    mWindowAdded = false;
+                }
             }
             // If user uses hard keyboard, IME button should always be shown.
             boolean showing = onEvaluateInputViewShown();
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index 4b60f07..1165281 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.Messenger;
 
 import com.android.internal.util.Preconditions;
 
@@ -155,4 +156,19 @@
     public void setDependencyMet(boolean met) {
         // Base tracker doesn't handle dependencies
     }
+
+    @Override
+    public void addStackedLink(LinkProperties link) {
+        mLinkProperties.addStackedLink(link);
+    }
+
+    @Override
+    public void removeStackedLink(LinkProperties link) {
+        mLinkProperties.removeStackedLink(link);
+    }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
 }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3a04c27..4e4980d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.provider.Settings;
 
@@ -1280,4 +1281,17 @@
         }
     }
 
+    /**
+     * Supply the backend messenger for a network tracker
+     *
+     * @param type NetworkType to set
+     * @param messenger {@link Messenger}
+     * {@hide}
+     */
+    public void supplyMessenger(int networkType, Messenger messenger) {
+        try {
+            mService.supplyMessenger(networkType, messenger);
+        } catch (RemoteException e) {
+        }
+    }
 }
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index fd22b10..1ebf393 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -77,7 +77,7 @@
         RENEW
     };
 
-    private String mInterfaceName;
+    private final String mInterfaceName;
     private boolean mRegisteredForPreDhcpNotification = false;
 
     private static final int BASE = Protocol.BASE_DHCP;
@@ -358,7 +358,7 @@
         } else if (dhcpAction == DhcpAction.RENEW) {
             if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
             success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpResults);
-            dhcpResults.updateFromDhcpRequest(mDhcpResults);
+            if (success) dhcpResults.updateFromDhcpRequest(mDhcpResults);
         }
         if (success) {
             if (DBG) Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java
index 39440c2..15a81f3 100644
--- a/core/java/android/net/DummyDataStateTracker.java
+++ b/core/java/android/net/DummyDataStateTracker.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Messenger;
 import android.util.Slog;
 
 /**
@@ -203,6 +204,21 @@
         // not supported on this network
     }
 
+    @Override
+    public void addStackedLink(LinkProperties link) {
+        mLinkProperties.addStackedLink(link);
+    }
+
+    @Override
+    public void removeStackedLink(LinkProperties link) {
+        mLinkProperties.removeStackedLink(link);
+    }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
+
     static private void log(String s) {
         Slog.d(TAG, s);
     }
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 8947162..27d5a58 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -22,6 +22,7 @@
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -407,4 +408,19 @@
     public void setDependencyMet(boolean met) {
         // not supported on this network
     }
+
+    @Override
+    public void addStackedLink(LinkProperties link) {
+        mLinkProperties.addStackedLink(link);
+    }
+
+    @Override
+    public void removeStackedLink(LinkProperties link) {
+        mLinkProperties.removeStackedLink(link);
+    }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 056fa03..9e9b43d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -22,6 +22,7 @@
 import android.net.NetworkState;
 import android.net.ProxyProperties;
 import android.os.IBinder;
+import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.net.LegacyVpnInfo;
@@ -126,4 +127,6 @@
     boolean updateLockdownVpn();
 
     void captivePortalCheckComplete(in NetworkInfo info);
+
+    void supplyMessenger(int networkType, in Messenger messenger);
 }
diff --git a/core/java/android/net/LinkCapabilities.java b/core/java/android/net/LinkCapabilities.java
index eb9166f..fb444ea 100644
--- a/core/java/android/net/LinkCapabilities.java
+++ b/core/java/android/net/LinkCapabilities.java
@@ -314,8 +314,8 @@
             sb.append(":\"");
             sb.append(entry.getValue());
             sb.append("\"");
-            return mCapabilities.toString();
         }
+        sb.append("}");
         return sb.toString();
     }
 
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index b9362da..75f8b59 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -22,10 +22,13 @@
 import android.text.TextUtils;
 
 import java.net.InetAddress;
+import java.net.Inet4Address;
+
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Hashtable;
 
 /**
  * Describes the properties of a network link.
@@ -47,10 +50,15 @@
  * don't care which is used.  The gateways will be
  * selected based on the destination address and the
  * source address has no relavence.
+ *
+ * Links can also be stacked on top of each other.
+ * This can be used, for example, to represent a tunnel
+ * interface that runs on top of a physical interface.
+ *
  * @hide
  */
 public class LinkProperties implements Parcelable {
-
+    // The interface described by the network link.
     private String mIfaceName;
     private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
     private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
@@ -58,6 +66,11 @@
     private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
     private ProxyProperties mHttpProxy;
 
+    // Stores the properties of links that are "stacked" above this link.
+    // Indexed by interface name to allow modification and to prevent duplicates being added.
+    private Hashtable<String, LinkProperties> mStackedLinks =
+        new Hashtable<String, LinkProperties>();
+
     public static class CompareResult<T> {
         public Collection<T> removed = new ArrayList<T>();
         public Collection<T> added = new ArrayList<T>();
@@ -87,17 +100,34 @@
             for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
             mHttpProxy = (source.getHttpProxy() == null)  ?
                     null : new ProxyProperties(source.getHttpProxy());
+            for (LinkProperties l: source.mStackedLinks.values()) {
+                addStackedLink(l);
+            }
         }
     }
 
     public void setInterfaceName(String iface) {
         mIfaceName = iface;
+        ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
+        for (RouteInfo route : mRoutes) {
+            newRoutes.add(routeWithInterface(route));
+        }
+        mRoutes = newRoutes;
     }
 
     public String getInterfaceName() {
         return mIfaceName;
     }
 
+    public Collection<String> getAllInterfaceNames() {
+        Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
+        if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
+        for (LinkProperties stacked: mStackedLinks.values()) {
+            interfaceNames.addAll(stacked.getAllInterfaceNames());
+        }
+        return interfaceNames;
+    }
+
     public Collection<InetAddress> getAddresses() {
         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
         for (LinkAddress linkAddress : mLinkAddresses) {
@@ -130,13 +160,44 @@
         mDomains = domains;
     }
 
-    public void addRoute(RouteInfo route) {
-        if (route != null) mRoutes.add(route);
+    private RouteInfo routeWithInterface(RouteInfo route) {
+        return new RouteInfo(
+            route.getDestination(),
+            route.getGateway(),
+            mIfaceName);
     }
+
+    public void addRoute(RouteInfo route) {
+        if (route != null) {
+            String routeIface = route.getInterface();
+            if (routeIface != null && !routeIface.equals(mIfaceName)) {
+                throw new IllegalArgumentException(
+                   "Route added with non-matching interface: " + routeIface +
+                   " vs. " + mIfaceName);
+            }
+            mRoutes.add(routeWithInterface(route));
+        }
+    }
+
+    /**
+     * Returns all the routes on this link.
+     */
     public Collection<RouteInfo> getRoutes() {
         return Collections.unmodifiableCollection(mRoutes);
     }
 
+    /**
+     * Returns all the routes on this link and all the links stacked above it.
+     */
+    public Collection<RouteInfo> getAllRoutes() {
+        Collection<RouteInfo> routes = new ArrayList();
+        routes.addAll(mRoutes);
+        for (LinkProperties stacked: mStackedLinks.values()) {
+            routes.addAll(stacked.getAllRoutes());
+        }
+        return routes;
+    }
+
     public void setHttpProxy(ProxyProperties proxy) {
         mHttpProxy = proxy;
     }
@@ -144,6 +205,46 @@
         return mHttpProxy;
     }
 
+    /**
+     * Adds a stacked link.
+     *
+     * If there is already a stacked link with the same interfacename as link,
+     * that link is replaced with link. Otherwise, link is added to the list
+     * of stacked links. If link is null, nothing changes.
+     *
+     * @param link The link to add.
+     */
+    public void addStackedLink(LinkProperties link) {
+        if (link != null && link.getInterfaceName() != null) {
+            mStackedLinks.put(link.getInterfaceName(), link);
+        }
+    }
+
+    /**
+     * Removes a stacked link.
+     *
+     * If there a stacked link with the same interfacename as link, it is
+     * removed. Otherwise, nothing changes.
+     *
+     * @param link The link to add.
+     */
+    public void removeStackedLink(LinkProperties link) {
+        if (link != null && link.getInterfaceName() != null) {
+            mStackedLinks.remove(link.getInterfaceName());
+        }
+    }
+
+    /**
+     * Returns all the links stacked on top of this link.
+     */
+    public Collection<LinkProperties> getStackedLinks() {
+        Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
+        for (LinkProperties link : mStackedLinks.values()) {
+          stacked.add(new LinkProperties(link));
+        }
+        return Collections.unmodifiableCollection(stacked);
+    }
+
     public void clear() {
         mIfaceName = null;
         mLinkAddresses.clear();
@@ -151,6 +252,7 @@
         mDomains = null;
         mRoutes.clear();
         mHttpProxy = null;
+        mStackedLinks.clear();
     }
 
     /**
@@ -180,7 +282,29 @@
         routes += "] ";
         String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
 
-        return ifaceName + linkAddresses + routes + dns + domainName + proxy;
+        String stacked = "";
+        if (mStackedLinks.values().size() > 0) {
+            stacked += " Stacked: [";
+            for (LinkProperties link: mStackedLinks.values()) {
+                stacked += " [" + link.toString() + " ],";
+            }
+            stacked += "] ";
+        }
+        return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}";
+    }
+
+    /**
+     * Returns true if this link has an IPv4 address.
+     *
+     * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
+     */
+    public boolean hasIPv4Address() {
+        for (LinkAddress address : mLinkAddresses) {
+          if (address.getAddress() instanceof Inet4Address) {
+            return true;
+          }
+        }
+        return false;
     }
 
     /**
@@ -247,6 +371,26 @@
                     getHttpProxy().equals(target.getHttpProxy());
     }
 
+    /**
+     * Compares this {@code LinkProperties} stacked links against the target
+     *
+     * @param target LinkProperties to compare.
+     * @return {@code true} if both are identical, {@code false} otherwise.
+     */
+    public boolean isIdenticalStackedLinks(LinkProperties target) {
+        if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
+            return false;
+        }
+        for (LinkProperties stacked : mStackedLinks.values()) {
+            // Hashtable values can never be null.
+            String iface = stacked.getInterfaceName();
+            if (!stacked.equals(target.mStackedLinks.get(iface))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     /**
      * Compares this {@code LinkProperties} instance against the target
@@ -259,6 +403,10 @@
      * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
      * 2. Worst case performance is O(n^2).
      *
+     * This method does not check that stacked interfaces are equal, because
+     * stacked interfaces are not so much a property of the link as a
+     * description of connections between links.
+     *
      * @param obj the object to be tested for equality.
      * @return {@code true} if both objects are equal, {@code false} otherwise.
      */
@@ -273,7 +421,8 @@
                 isIdenticalAddresses(target) &&
                 isIdenticalDnses(target) &&
                 isIdenticalRoutes(target) &&
-                isIdenticalHttpProxy(target);
+                isIdenticalHttpProxy(target) &&
+                isIdenticalStackedLinks(target);
     }
 
     /**
@@ -349,16 +498,16 @@
     public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
         /*
          * Duplicate the RouteInfos into removed, we will be removing
-         * routes which are common between mDnses and target
+         * routes which are common between mRoutes and target
          * leaving the routes that are different. And route address which
          * are in target but not in mRoutes are placed in added.
          */
         CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
 
-        result.removed = new ArrayList<RouteInfo>(mRoutes);
+        result.removed = getAllRoutes();
         result.added.clear();
         if (target != null) {
-            for (RouteInfo r : target.getRoutes()) {
+            for (RouteInfo r : target.getAllRoutes()) {
                 if (! result.removed.remove(r)) {
                     result.added.add(r);
                 }
@@ -380,7 +529,8 @@
                 + mDnses.size() * 37
                 + ((null == mDomains) ? 0 : mDomains.hashCode())
                 + mRoutes.size() * 41
-                + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
+                + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
+                + mStackedLinks.hashCode() * 47);
     }
 
     /**
@@ -410,6 +560,8 @@
         } else {
             dest.writeByte((byte)0);
         }
+        ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
+        dest.writeList(stackedLinks);
     }
 
     /**
@@ -442,6 +594,11 @@
                 if (in.readByte() == 1) {
                     netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
                 }
+                ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
+                in.readList(stackedLinks, LinkProperties.class.getClassLoader());
+                for (LinkProperties stackedLink: stackedLinks) {
+                    netProp.addStackedLink(stackedLink);
+                }
                 return netProp;
             }
 
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index b35d61c..e85dbcd 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -74,7 +74,6 @@
 
     private Handler mHandler;
     private AsyncChannel mDataConnectionTrackerAc;
-    private Messenger mMessenger;
 
     /**
      * Create a new MobileDataStateTracker
@@ -103,7 +102,6 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
-        filter.addAction(DctConstants.ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
 
         mContext.registerReceiver(new MobileDataStateReceiver(), filter);
         mMobileDataState = PhoneConstants.DataState.DISCONNECTED;
@@ -285,13 +283,6 @@
                                 " broadcast" + reason == null ? "" : "(" + reason + ")");
                 }
                 setDetailedState(DetailedState.FAILED, reason, apnName);
-            } else if (intent.getAction().equals(DctConstants
-                    .ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
-                if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
-                mMessenger =
-                    intent.getParcelableExtra(DctConstants.EXTRA_MESSENGER);
-                AsyncChannel ac = new AsyncChannel();
-                ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger);
             } else {
                 if (DBG) log("Broadcast received: ignore " + intent.getAction());
             }
@@ -522,6 +513,16 @@
     }
 
     @Override
+    public void addStackedLink(LinkProperties link) {
+        mLinkProperties.addStackedLink(link);
+    }
+
+    @Override
+    public void removeStackedLink(LinkProperties link) {
+        mLinkProperties.removeStackedLink(link);
+    }
+
+    @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
         final PrintWriter pw = new PrintWriter(writer);
@@ -603,6 +604,12 @@
         return new LinkCapabilities(mLinkCapabilities);
     }
 
+    public void supplyMessenger(Messenger messenger) {
+        if (VDBG) log(mApnType + " got supplyMessenger");
+        AsyncChannel ac = new AsyncChannel();
+        ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger);
+    }
+
     private void log(String s) {
         Slog.d(TAG, mApnType + ": " + s);
     }
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 0a0c1e0..cf77a1c 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -18,6 +18,9 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.Messenger;
+
+import static com.android.internal.util.Protocol.BASE_NETWORK_STATE_TRACKER;
 
 /**
  * Interface provides the {@link com.android.server.ConnectivityService}
@@ -48,25 +51,38 @@
      * msg.what = EVENT_STATE_CHANGED
      * msg.obj = NetworkInfo object
      */
-    public static final int EVENT_STATE_CHANGED = 1;
+    public static final int EVENT_STATE_CHANGED = BASE_NETWORK_STATE_TRACKER;
 
     /**
      * msg.what = EVENT_CONFIGURATION_CHANGED
      * msg.obj = NetworkInfo object
      */
-    public static final int EVENT_CONFIGURATION_CHANGED = 3;
+    public static final int EVENT_CONFIGURATION_CHANGED = BASE_NETWORK_STATE_TRACKER + 1;
 
     /**
      * msg.what = EVENT_RESTORE_DEFAULT_NETWORK
      * msg.obj = FeatureUser object
      */
-    public static final int EVENT_RESTORE_DEFAULT_NETWORK = 6;
+    public static final int EVENT_RESTORE_DEFAULT_NETWORK = BASE_NETWORK_STATE_TRACKER + 2;
 
     /**
      * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED
      * msg.obj = NetworkInfo object
      */
-    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 7;
+    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = BASE_NETWORK_STATE_TRACKER + 3;
+
+    /**
+     * msg.what = EVENT_NETWORK_CONNECTED
+     * msg.obj = LinkProperties object
+     */
+    public static final int EVENT_NETWORK_CONNECTED = BASE_NETWORK_STATE_TRACKER + 4;
+
+    /**
+     * msg.what = EVENT_NETWORK_CONNECTION_DISCONNECTED
+     * msg.obj = LinkProperties object, same iface name
+     */
+    public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5;
+
 
     /**
      * -------------------------------------------------------------
@@ -197,4 +213,20 @@
      * An external dependency has been met/unmet
      */
     public void setDependencyMet(boolean met);
+
+    /**
+     * Informs the state tracker that another interface is stacked on top of it.
+     **/
+    public void addStackedLink(LinkProperties link);
+
+    /**
+     * Informs the state tracker that a stacked interface has been removed.
+     **/
+    public void removeStackedLink(LinkProperties link);
+
+    /*
+     * Called once to setup async channel between this and
+     * the underlying network specific code.
+     */
+    public void supplyMessenger(Messenger messenger);
 }
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 112e143..cc3c5f7 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -29,6 +29,17 @@
 /**
  * A simple container for route information.
  *
+ * In order to be used, a route must have a destination prefix and:
+ *
+ * - A gateway address (next-hop, for gatewayed routes), or
+ * - An interface (for directly-connected routes), or
+ * - Both a gateway and an interface.
+ *
+ * This class does not enforce these constraints because there is code that
+ * uses RouteInfo objects to store directly-connected routes without interfaces.
+ * Such objects cannot be used directly, but can be put into a LinkProperties
+ * object which then specifies the interface.
+ *
  * @hide
  */
 public class RouteInfo implements Parcelable {
@@ -42,10 +53,30 @@
      */
     private final InetAddress mGateway;
 
+    /**
+     * The interface for this route.
+     */
+    private final String mInterface;
+
     private final boolean mIsDefault;
     private final boolean mIsHost;
 
-    public RouteInfo(LinkAddress destination, InetAddress gateway) {
+    /**
+     * Constructs a RouteInfo object.
+     *
+     * If destination is null, then gateway must be specified and the
+     * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+     * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default
+     * route <code>::/0</code> if gateway is an instance of
+     * {@link Inet6Address}.
+     *
+     * destination and gateway may not both be null.
+     *
+     * @param destination the destination prefix
+     * @param gateway the IP address to route packets through
+     * @param iface the interface name to send packets on
+     */
+    public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
         if (destination == null) {
             if (gateway != null) {
                 if (gateway instanceof Inet4Address) {
@@ -55,7 +86,8 @@
                 }
             } else {
                 // no destination, no gateway. invalid.
-                throw new RuntimeException("Invalid arguments passed in.");
+                throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
+                                                   destination);
             }
         }
         if (gateway == null) {
@@ -68,34 +100,42 @@
         mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
                 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
         mGateway = gateway;
+        mInterface = iface;
         mIsDefault = isDefault();
         mIsHost = isHost();
     }
 
+    public RouteInfo(LinkAddress destination, InetAddress gateway) {
+        this(destination, gateway, null);
+    }
+
     public RouteInfo(InetAddress gateway) {
-        this(null, gateway);
+        this(null, gateway, null);
     }
 
     public RouteInfo(LinkAddress host) {
-        this(host, null);
+        this(host, null, null);
     }
 
-    public static RouteInfo makeHostRoute(InetAddress host) {
-        return makeHostRoute(host, null);
+    public static RouteInfo makeHostRoute(InetAddress host, String iface) {
+        return makeHostRoute(host, null, iface);
     }
 
-    public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) {
+    public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
         if (host == null) return null;
 
         if (host instanceof Inet4Address) {
-            return new RouteInfo(new LinkAddress(host, 32), gateway);
+            return new RouteInfo(new LinkAddress(host, 32), gateway, iface);
         } else {
-            return new RouteInfo(new LinkAddress(host, 128), gateway);
+            return new RouteInfo(new LinkAddress(host, 128), gateway, iface);
         }
     }
 
     private boolean isHost() {
-        return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY));
+        return (mDestination.getAddress() instanceof Inet4Address &&
+                mDestination.getNetworkPrefixLength() == 32) ||
+               (mDestination.getAddress() instanceof Inet6Address &&
+                mDestination.getNetworkPrefixLength() == 128);
     }
 
     private boolean isDefault() {
@@ -119,6 +159,10 @@
         return mGateway;
     }
 
+    public String getInterface() {
+        return mInterface;
+    }
+
     public boolean isDefaultRoute() {
         return mIsDefault;
     }
@@ -153,6 +197,8 @@
             dest.writeByte((byte) 1);
             dest.writeByteArray(mGateway.getAddress());
         }
+
+        dest.writeString(mInterface);
     }
 
     @Override
@@ -171,14 +217,19 @@
                 target.getGateway() == null
                 : mGateway.equals(target.getGateway());
 
-        return sameDestination && sameAddress
+        boolean sameInterface = (mInterface == null) ?
+                target.getInterface() == null
+                : mInterface.equals(target.getInterface());
+
+        return sameDestination && sameAddress && sameInterface
             && mIsDefault == target.mIsDefault;
     }
 
     @Override
     public int hashCode() {
-        return (mDestination == null ? 0 : mDestination.hashCode())
-            + (mGateway == null ? 0 :mGateway.hashCode())
+        return (mDestination == null ? 0 : mDestination.hashCode() * 41)
+            + (mGateway == null ? 0 :mGateway.hashCode() * 47)
+            + (mInterface == null ? 0 :mInterface.hashCode() * 67)
             + (mIsDefault ? 3 : 7);
     }
 
@@ -206,13 +257,15 @@
                 } catch (UnknownHostException e) {}
             }
 
+            String iface = in.readString();
+
             LinkAddress dest = null;
 
             if (destAddr != null) {
                 dest = new LinkAddress(destAddr, prefix);
             }
 
-            return new RouteInfo(dest, gateway);
+            return new RouteInfo(dest, gateway, iface);
         }
 
         public RouteInfo[] newArray(int size) {
@@ -220,13 +273,9 @@
         }
     };
 
-    private boolean matches(InetAddress destination) {
+    protected boolean matches(InetAddress destination) {
         if (destination == null) return false;
 
-        // if the destination is present and the route is default.
-        // return true
-        if (isDefault()) return true;
-
         // match the route destination and destination with prefix length
         InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
                 mDestination.getNetworkPrefixLength());
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index c0a894b..2a2f7cf 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -23,8 +23,8 @@
 import java.net.Socket;
 import java.net.SocketException;
 import java.security.KeyManagementException;
+import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
-import java.security.interfaces.ECPrivateKey;
 import javax.net.SocketFactory;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
@@ -89,7 +89,7 @@
     private TrustManager[] mTrustManagers = null;
     private KeyManager[] mKeyManagers = null;
     private byte[] mNpnProtocols = null;
-    private ECPrivateKey mChannelIdPrivateKey = null;
+    private PrivateKey mChannelIdPrivateKey = null;
 
     private final int mHandshakeTimeoutMillis;
     private final SSLClientSessionCache mSessionCache;
@@ -321,7 +321,7 @@
     }
 
     /**
-     * Sets the {@link ECPrivateKey} to be used for TLS Channel ID by connections made by this
+     * Sets the private key to be used for TLS Channel ID by connections made by this
      * factory.
      *
      * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables
@@ -330,7 +330,7 @@
      *
      * @hide
      */
-    public void setChannelIdPrivateKey(ECPrivateKey privateKey) {
+    public void setChannelIdPrivateKey(PrivateKey privateKey) {
         mChannelIdPrivateKey = privateKey;
     }
 
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index ce1276f..786439e5 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -119,6 +119,8 @@
      * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and
      * used internally by system services like {@link DownloadManager} when
      * performing traffic on behalf of an application.
+     *
+     * @see #clearThreadStatsTag()
      */
     public static void setThreadStatsTag(int tag) {
         NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
@@ -128,11 +130,19 @@
      * Get the active tag used when accounting {@link Socket} traffic originating
      * from the current thread. Only one active tag per thread is supported.
      * {@link #tagSocket(Socket)}.
+     *
+     * @see #setThreadStatsTag(int)
      */
     public static int getThreadStatsTag() {
         return NetworkManagementSocketTagger.getThreadSocketStatsTag();
     }
 
+    /**
+     * Clear any active tag set to account {@link Socket} traffic originating
+     * from the current thread.
+     *
+     * @see #setThreadStatsTag(int)
+     */
     public static void clearThreadStatsTag() {
         NetworkManagementSocketTagger.setThreadSocketStatsTag(-1);
     }
@@ -148,7 +158,7 @@
      * To take effect, caller must hold
      * {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission.
      *
-     * {@hide}
+     * @hide
      */
     public static void setThreadStatsUid(int uid) {
         NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
@@ -260,10 +270,13 @@
     }
 
     /**
-     * Get the total number of packets transmitted through the mobile interface.
-     *
-     * @return number of packets.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of packets transmitted across mobile networks since device
+     * boot. Counts packets across all mobile network interfaces, and always
+     * increases monotonically since device boot. Statistics are measured at the
+     * network layer, so they include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getMobileTxPackets() {
         long total = 0;
@@ -274,10 +287,13 @@
     }
 
     /**
-     * Get the total number of packets received through the mobile interface.
-     *
-     * @return number of packets.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of packets received across mobile networks since device
+     * boot. Counts packets across all mobile network interfaces, and always
+     * increases monotonically since device boot. Statistics are measured at the
+     * network layer, so they include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getMobileRxPackets() {
         long total = 0;
@@ -288,10 +304,13 @@
     }
 
     /**
-     * Get the total number of bytes transmitted through the mobile interface.
-     *
-     * @return number of bytes.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of bytes transmitted across mobile networks since device
+     * boot. Counts packets across all mobile network interfaces, and always
+     * increases monotonically since device boot. Statistics are measured at the
+     * network layer, so they include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getMobileTxBytes() {
         long total = 0;
@@ -302,10 +321,13 @@
     }
 
     /**
-     * Get the total number of bytes received through the mobile interface.
-     *
-     * @return number of bytes.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of bytes received across mobile networks since device boot.
+     * Counts packets across all mobile network interfaces, and always increases
+     * monotonically since device boot. Statistics are measured at the network
+     * layer, so they include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getMobileRxBytes() {
         long total = 0;
@@ -339,85 +361,73 @@
         return total;
     }
 
-    /**
-     * Get the total number of packets transmitted through the specified interface.
-     *
-     * @return number of packets.  If the statistics are not supported by this interface,
-     * {@link #UNSUPPORTED} will be returned.
-     * @hide
-     */
+    /** {@hide} */
     public static long getTxPackets(String iface) {
         return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
     }
 
-    /**
-     * Get the total number of packets received through the specified interface.
-     *
-     * @return number of packets.  If the statistics are not supported by this interface,
-     * {@link #UNSUPPORTED} will be returned.
-     * @hide
-     */
+    /** {@hide} */
     public static long getRxPackets(String iface) {
         return nativeGetIfaceStat(iface, TYPE_RX_PACKETS);
     }
 
-    /**
-     * Get the total number of bytes transmitted through the specified interface.
-     *
-     * @return number of bytes.  If the statistics are not supported by this interface,
-     * {@link #UNSUPPORTED} will be returned.
-     * @hide
-     */
+    /** {@hide} */
     public static long getTxBytes(String iface) {
         return nativeGetIfaceStat(iface, TYPE_TX_BYTES);
     }
 
-    /**
-     * Get the total number of bytes received through the specified interface.
-     *
-     * @return number of bytes.  If the statistics are not supported by this interface,
-     * {@link #UNSUPPORTED} will be returned.
-     * @hide
-     */
+    /** {@hide} */
     public static long getRxBytes(String iface) {
         return nativeGetIfaceStat(iface, TYPE_RX_BYTES);
     }
 
     /**
-     * Get the total number of packets sent through all network interfaces.
-     *
-     * @return the number of packets.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of packets transmitted since device boot. Counts packets
+     * across all network interfaces, and always increases monotonically since
+     * device boot. Statistics are measured at the network layer, so they
+     * include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getTotalTxPackets() {
         return nativeGetTotalStat(TYPE_TX_PACKETS);
     }
 
     /**
-     * Get the total number of packets received through all network interfaces.
-     *
-     * @return number of packets.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of packets received since device boot. Counts packets
+     * across all network interfaces, and always increases monotonically since
+     * device boot. Statistics are measured at the network layer, so they
+     * include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getTotalRxPackets() {
         return nativeGetTotalStat(TYPE_RX_PACKETS);
     }
 
     /**
-     * Get the total number of bytes sent through all network interfaces.
-     *
-     * @return number of bytes.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of bytes transmitted since device boot. Counts packets
+     * across all network interfaces, and always increases monotonically since
+     * device boot. Statistics are measured at the network layer, so they
+     * include both TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getTotalTxBytes() {
         return nativeGetTotalStat(TYPE_TX_BYTES);
     }
 
     /**
-     * Get the total number of bytes received through all network interfaces.
-     *
-     * @return number of bytes.  If the statistics are not supported by this device,
-     * {@link #UNSUPPORTED} will be returned.
+     * Return number of bytes received since device boot. Counts packets across
+     * all network interfaces, and always increases monotonically since device
+     * boot. Statistics are measured at the network layer, so they include both
+     * TCP and UDP usage.
+     * <p>
+     * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+     * return {@link #UNSUPPORTED} on devices where statistics aren't available.
      */
     public static long getTotalRxBytes() {
         return nativeGetTotalStat(TYPE_RX_BYTES);
@@ -580,6 +590,7 @@
      * special permission.
      */
     private static NetworkStats getDataLayerSnapshotForUid(Context context) {
+        // TODO: take snapshot locally, since proc file is now visible
         final int uid = android.os.Process.myUid();
         try {
             return getStatsService().getDataLayerSnapshotForUid(uid);
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index cc6903d..4b022d9 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Environment.UserEnvironment;
+import android.os.StrictMode;
 import android.util.Log;
 import java.io.File;
 import java.io.IOException;
@@ -2326,4 +2327,16 @@
             return this;
         }
     }
+
+    /**
+     * If this is a {@code file://} Uri, it will be reported to
+     * {@link StrictMode}.
+     *
+     * @hide
+     */
+    public void checkFileUriExposed(String location) {
+        if ("file".equals(getScheme())) {
+            StrictMode.onFileUriExposed(location);
+        }
+    }
 }
diff --git a/core/java/android/nfc/BeamShareData.aidl b/core/java/android/nfc/BeamShareData.aidl
new file mode 100644
index 0000000..a47e240
--- /dev/null
+++ b/core/java/android/nfc/BeamShareData.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.nfc;
+
+parcelable BeamShareData;
diff --git a/core/java/android/nfc/BeamShareData.java b/core/java/android/nfc/BeamShareData.java
new file mode 100644
index 0000000..c30ba14
--- /dev/null
+++ b/core/java/android/nfc/BeamShareData.java
@@ -0,0 +1,62 @@
+package android.nfc;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class to IPC data to be shared over Android Beam.
+ * Allows bundling NdefMessage, Uris and flags in a single
+ * IPC call. This is important as we want to reduce the
+ * amount of IPC calls at "touch time".
+ * @hide
+ */
+public final class BeamShareData implements Parcelable {
+    public final NdefMessage ndefMessage;
+    public final Uri[] uris;
+    public final int flags;
+
+    public BeamShareData(NdefMessage msg, Uri[] uris, int flags) {
+        this.ndefMessage = msg;
+        this.uris = uris;
+        this.flags = flags;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        int urisLength = (uris != null) ? uris.length : 0;
+        dest.writeParcelable(ndefMessage, 0);
+        dest.writeInt(urisLength);
+        if (urisLength > 0) {
+            dest.writeTypedArray(uris, 0);
+        }
+        dest.writeInt(this.flags);
+    }
+
+    public static final Parcelable.Creator<BeamShareData> CREATOR =
+            new Parcelable.Creator<BeamShareData>() {
+        @Override
+        public BeamShareData createFromParcel(Parcel source) {
+            Uri[] uris = null;
+            NdefMessage msg = source.readParcelable(NdefMessage.class.getClassLoader());
+            int numUris = source.readInt();
+            if (numUris > 0) {
+                uris = new Uri[numUris];
+                source.readTypedArray(uris, Uri.CREATOR);
+            }
+            int flags = source.readInt();
+
+            return new BeamShareData(msg, uris, flags);
+        }
+
+        @Override
+        public BeamShareData[] newArray(int size) {
+            return new BeamShareData[size];
+        }
+    };
+}
diff --git a/core/java/android/nfc/INdefPushCallback.aidl b/core/java/android/nfc/INdefPushCallback.aidl
index 1c6d5d0..16771dc 100644
--- a/core/java/android/nfc/INdefPushCallback.aidl
+++ b/core/java/android/nfc/INdefPushCallback.aidl
@@ -16,15 +16,13 @@
 
 package android.nfc;
 
-import android.nfc.NdefMessage;
-import android.net.Uri;
+import android.nfc.BeamShareData;
 
 /**
  * @hide
  */
 interface INdefPushCallback
 {
-    NdefMessage createMessage();
-    Uri[] getUris();
+    BeamShareData createBeamShareData();
     void onNdefPushComplete();
 }
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 7c3123f..10183c0 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -110,6 +110,7 @@
         NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
         NfcAdapter.CreateBeamUrisCallback uriCallback = null;
         Uri[] uris = null;
+        int flags = 0;
         public NfcActivityState(Activity activity) {
             if (activity.getWindow().isDestroyed()) {
                 throw new IllegalStateException("activity is already destroyed");
@@ -215,11 +216,12 @@
         }
     }
 
-    public void setNdefPushMessage(Activity activity, NdefMessage message) {
+    public void setNdefPushMessage(Activity activity, NdefMessage message, int flags) {
         boolean isResumed;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = getActivityState(activity);
             state.ndefMessage = message;
+            state.flags = flags;
             isResumed = state.resumed;
         }
         if (isResumed) {
@@ -228,11 +230,12 @@
     }
 
     public void setNdefPushMessageCallback(Activity activity,
-            NfcAdapter.CreateNdefMessageCallback callback) {
+            NfcAdapter.CreateNdefMessageCallback callback, int flags) {
         boolean isResumed;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = getActivityState(activity);
             state.ndefMessageCallback = callback;
+            state.flags = flags;
             isResumed = state.resumed;
         }
         if (isResumed) {
@@ -267,38 +270,29 @@
 
     /** Callback from NFC service, usually on binder thread */
     @Override
-    public NdefMessage createMessage() {
-        NfcAdapter.CreateNdefMessageCallback callback;
+    public BeamShareData createBeamShareData() {
+        NfcAdapter.CreateNdefMessageCallback ndefCallback;
+        NfcAdapter.CreateBeamUrisCallback urisCallback;
         NdefMessage message;
-        synchronized (NfcActivityManager.this) {
-            NfcActivityState state = findResumedActivityState();
-            if (state == null) return null;
-
-            callback = state.ndefMessageCallback;
-            message = state.ndefMessage;
-        }
-
-        // Make callback without lock
-        if (callback != null) {
-            return callback.createNdefMessage(mDefaultEvent);
-        } else {
-            return message;
-        }
-    }
-
-    /** Callback from NFC service, usually on binder thread */
-    @Override
-    public Uri[] getUris() {
         Uri[] uris;
-        NfcAdapter.CreateBeamUrisCallback callback;
+        int flags;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = findResumedActivityState();
             if (state == null) return null;
+
+            ndefCallback = state.ndefMessageCallback;
+            urisCallback = state.uriCallback;
+            message = state.ndefMessage;
             uris = state.uris;
-            callback = state.uriCallback;
+            flags = state.flags;
         }
-        if (callback != null) {
-            uris = callback.createBeamUris(mDefaultEvent);
+
+        // Make callbacks without lock
+        if (ndefCallback != null) {
+            message  = ndefCallback.createNdefMessage(mDefaultEvent);
+        }
+        if (urisCallback != null) {
+            uris = urisCallback.createBeamUris(mDefaultEvent);
             if (uris != null) {
                 for (Uri uri : uris) {
                     if (uri == null) {
@@ -314,10 +308,9 @@
                     }
                 }
             }
-            return uris;
-        } else {
-            return uris;
         }
+
+        return new BeamShareData(message, uris, flags);
     }
 
     /** Callback from NFC service, usually on binder thread */
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 6ad382b..ca4a7d6 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -196,6 +196,9 @@
     public static final int STATE_TURNING_OFF = 4;
 
     /** @hide */
+    public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
+
+    /** @hide */
     public static final String ACTION_HANDOVER_TRANSFER_STARTED =
             "android.nfc.action.HANDOVER_TRANSFER_STARTED";
 
@@ -796,12 +799,12 @@
             if (activity == null) {
                 throw new NullPointerException("activity cannot be null");
             }
-            mNfcActivityManager.setNdefPushMessage(activity, message);
+            mNfcActivityManager.setNdefPushMessage(activity, message, 0);
             for (Activity a : activities) {
                 if (a == null) {
                     throw new NullPointerException("activities cannot contain null");
                 }
-                mNfcActivityManager.setNdefPushMessage(a, message);
+                mNfcActivityManager.setNdefPushMessage(a, message, 0);
             }
         } catch (IllegalStateException e) {
             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
@@ -816,6 +819,16 @@
     }
 
     /**
+     * @hide
+     */
+    public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
+        if (activity == null) {
+            throw new NullPointerException("activity cannot be null");
+        }
+        mNfcActivityManager.setNdefPushMessage(activity, message, flags);
+    }
+
+    /**
      * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM).
      *
      * <p>This method may be called at any time before {@link Activity#onDestroy},
@@ -887,12 +900,12 @@
             if (activity == null) {
                 throw new NullPointerException("activity cannot be null");
             }
-            mNfcActivityManager.setNdefPushMessageCallback(activity, callback);
+            mNfcActivityManager.setNdefPushMessageCallback(activity, callback, 0);
             for (Activity a : activities) {
                 if (a == null) {
                     throw new NullPointerException("activities cannot contain null");
                 }
-                mNfcActivityManager.setNdefPushMessageCallback(a, callback);
+                mNfcActivityManager.setNdefPushMessageCallback(a, callback, 0);
             }
         } catch (IllegalStateException e) {
             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
@@ -907,6 +920,17 @@
     }
 
     /**
+     * @hide
+     */
+    public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
+            int flags) {
+        if (activity == null) {
+            throw new NullPointerException("activity cannot be null");
+        }
+        mNfcActivityManager.setNdefPushMessageCallback(activity, callback, flags);
+    }
+
+    /**
      * Set a callback on successful Android Beam (TM).
      *
      * <p>This method may be called at any time before {@link Activity#onDestroy},
@@ -1095,7 +1119,7 @@
             throw new NullPointerException();
         }
         enforceResumed(activity);
-        mNfcActivityManager.setNdefPushMessage(activity, message);
+        mNfcActivityManager.setNdefPushMessage(activity, message, 0);
     }
 
     /**
@@ -1123,8 +1147,8 @@
             throw new NullPointerException();
         }
         enforceResumed(activity);
-        mNfcActivityManager.setNdefPushMessage(activity, null);
-        mNfcActivityManager.setNdefPushMessageCallback(activity, null);
+        mNfcActivityManager.setNdefPushMessage(activity, null, 0);
+        mNfcActivityManager.setNdefPushMessageCallback(activity, null, 0);
         mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null);
     }
 
diff --git a/core/java/android/nfc/tech/NfcBarcode.java b/core/java/android/nfc/tech/NfcBarcode.java
index 3149857..76627de 100644
--- a/core/java/android/nfc/tech/NfcBarcode.java
+++ b/core/java/android/nfc/tech/NfcBarcode.java
@@ -86,6 +86,28 @@
     /**
      * Returns the barcode of an NfcBarcode tag.
      *
+     * <p> Tags of {@link #TYPE_KOVIO} return 16 bytes:
+     *     <ul>
+     *     <p> The first byte is 0x80 ORd with a manufacturer ID, corresponding
+     *       to ISO/IEC 7816-6.
+     *     <p> The second byte describes the payload data format. Defined data
+     *       format types include the following:<ul>
+     *       <li>0x00: Reserved for manufacturer assignment</li>
+     *       <li>0x01: 96-bit URL with "http://www." prefix</li>
+     *       <li>0x02: 96-bit URL with "https://www." prefix</li>
+     *       <li>0x03: 96-bit URL with "http://" prefix</li>
+     *       <li>0x04: 96-bit URL with "https://" prefix</li>
+     *       <li>0x05: 96-bit GS1 EPC</li>
+     *       <li>0x06-0xFF: reserved</li>
+     *       </ul>
+     *     <p>The following 12 bytes are payload:<ul>
+     *       <li> In case of a URL payload, the payload is encoded in US-ASCII,
+     *            following the limitations defined in RF3987,
+     *            {@see http://www.ietf.org/rfc/rfc3987.txt}</li>
+     *       <li> In case of GS1 EPC daya, {@see http://www.gs1.org/gsmp/kc/epcglobal/tds/}
+     *            for more details.</li></ul>
+     *     <p>The last 2 bytes comprise the CRC.
+     *     </ul>
      * <p>Does not cause any RF activity and does not block.
      *
      * @return a byte array containing the barcode
diff --git a/core/java/android/nfc/tech/TagTechnology.java b/core/java/android/nfc/tech/TagTechnology.java
index 3493ea7..0e2c7c1 100644
--- a/core/java/android/nfc/tech/TagTechnology.java
+++ b/core/java/android/nfc/tech/TagTechnology.java
@@ -50,6 +50,7 @@
  * <ul>
  * <li>{@link MifareClassic}
  * <li>{@link MifareUltralight}
+ * <li>{@link NfcBarcode}
  * <li>{@link NdefFormatable} must only be enumerated on tags for which this Android device
  * is capable of formatting. Proprietary knowledge is often required to format a tag
  * to make it NDEF compatible.
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 16b4835..e9e7551 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -152,7 +152,15 @@
      * not return until the current process is exiting.
      */
     public static final native void joinThreadPool();
-    
+
+    /**
+     * Returns true if the specified interface is a proxy.
+     * @hide
+     */
+    public static final boolean isProxy(IInterface iface) {
+        return iface.asBinder() != iface;
+    }
+
     /**
      * Default constructor initializes the object.
      */
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 18a0018..b8769b4 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -218,7 +218,7 @@
             return;
         }
         if (mMap == null) {
-            mMap = new HashMap<String, Object>();
+            mMap = new HashMap<String, Object>(N);
         }
         mParcelledData.readMapInternal(mMap, N, mClassLoader);
         mParcelledData.recycle();
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 2bec1c1..9666d9a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.util.Log;
+
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -25,6 +27,8 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.regex.Pattern;
 import java.util.zip.CRC32;
 import java.util.zip.CheckedInputStream;
@@ -34,6 +38,8 @@
  * @hide
  */
 public class FileUtils {
+    private static final String TAG = "FileUtils";
+
     public static final int S_IRWXU = 00700;
     public static final int S_IRUSR = 00400;
     public static final int S_IWUSR = 00200;
@@ -161,7 +167,8 @@
             } else if (max < 0) {  // "tail" mode: keep the last N
                 int len;
                 boolean rolled = false;
-                byte[] last = null, data = null;
+                byte[] last = null;
+                byte[] data = null;
                 do {
                     if (last != null) rolled = true;
                     byte[] tmp = last; last = data; data = tmp;
@@ -237,4 +244,40 @@
             }
         }
     }
+
+    /**
+     * Delete older files in a directory until only those matching the given
+     * constraints remain.
+     *
+     * @param minCount Always keep at least this many files.
+     * @param minAge Always keep files younger than this age.
+     */
+    public static void deleteOlderFiles(File dir, int minCount, long minAge) {
+        if (minCount < 0 || minAge < 0) {
+            throw new IllegalArgumentException("Constraints must be positive or 0");
+        }
+
+        final File[] files = dir.listFiles();
+        if (files == null) return;
+
+        // Sort with newest files first
+        Arrays.sort(files, new Comparator<File>() {
+            @Override
+            public int compare(File lhs, File rhs) {
+                return (int) (rhs.lastModified() - lhs.lastModified());
+            }
+        });
+
+        // Keep at least minCount files
+        for (int i = minCount; i < files.length; i++) {
+            final File file = files[i];
+
+            // Keep files newer than minAge
+            final long age = System.currentTimeMillis() - file.lastModified();
+            if (age > minAge) {
+                Log.d(TAG, "Deleting old file " + file);
+                file.delete();
+            }
+        }
+    }
 }
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 4b83611..45524c8 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -152,16 +152,6 @@
     boolean isTetheringStarted();
 
     /**
-     * Start bluetooth reverse tethering services
-     */
-    void startReverseTethering(in String iface);
-
-    /**
-     * Stop currently running bluetooth reserse tethering services
-     */
-    void stopReverseTethering();
-
-    /**
      * Tethers the specified interface
      */
     void tetherInterface(String iface);
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 34c9740..2e8092a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -20,6 +20,7 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.content.pm.UserInfo;
+import android.content.RestrictionEntry;
 import android.graphics.Bitmap;
 
 /**
@@ -33,6 +34,7 @@
     Bitmap getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
     UserInfo getUserInfo(int userHandle);
+    boolean isRestricted();
     void setGuestEnabled(boolean enable);
     boolean isGuestEnabled();
     void wipeUser(int userHandle);
@@ -40,4 +42,7 @@
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
     void setUserRestrictions(in Bundle restrictions, int userHandle);
+    void setApplicationRestrictions(in String packageName, in List<RestrictionEntry> entries,
+            int userHandle);
+    List<RestrictionEntry> getApplicationRestrictions(in String packageName, int userHandle);
 }
diff --git a/core/java/android/os/LatencyTimer.java b/core/java/android/os/LatencyTimer.java
deleted file mode 100644
index ed2f0f9..0000000
--- a/core/java/android/os/LatencyTimer.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 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.os;
-
-import android.util.Log;
-
-import java.util.HashMap;
-
-/**
- * A class to help with measuring latency in your code.
- * 
- * Suggested usage:
- * 1) Instanciate a LatencyTimer as a class field.
- *      private [static] LatencyTimer mLt = new LatencyTimer(100, 1000);
- * 2) At various points in the code call sample with a string and the time delta to some fixed time.
- *    The string should be unique at each point of the code you are measuring.
- *      mLt.sample("before processing event", System.nanoTime() - event.getEventTimeNano());
- *      processEvent(event);
- *      mLt.sample("after processing event ", System.nanoTime() - event.getEventTimeNano());
- *
- * @hide
- */
-public final class LatencyTimer
-{
-    final String TAG = "LatencyTimer";
-    final int mSampleSize;
-    final int mScaleFactor;
-    volatile HashMap<String, long[]> store = new HashMap<String, long[]>();
-
-    /**
-    * Creates a LatencyTimer object
-    * @param sampleSize number of samples to collect before printing out the average
-    * @param scaleFactor divisor used to make each sample smaller to prevent overflow when
-    *        (sampleSize * average sample value)/scaleFactor > Long.MAX_VALUE
-    */
-    public LatencyTimer(int sampleSize, int scaleFactor) {
-        if (scaleFactor == 0) {
-            scaleFactor = 1;
-        }
-        mScaleFactor = scaleFactor;
-        mSampleSize = sampleSize;
-    }
-
-    /**
-     * Add a sample delay for averaging.
-     * @param tag string used for printing out the result. This should be unique at each point of
-     *  this called.
-     * @param delta time difference from an unique point of reference for a particular iteration
-     */
-    public void sample(String tag, long delta) {
-        long[] array = getArray(tag);
-
-        // array[mSampleSize] holds the number of used entries
-        final int index = (int) array[mSampleSize]++;
-        array[index] = delta;
-        if (array[mSampleSize] == mSampleSize) {
-            long totalDelta = 0;
-            for (long d : array) {
-                totalDelta += d/mScaleFactor;
-            }
-            array[mSampleSize] = 0;
-            Log.i(TAG, tag + " average = " + totalDelta / mSampleSize);
-        }
-    }
-
-    private long[] getArray(String tag) {
-        long[] data = store.get(tag);
-        if (data == null) {
-            synchronized(store) {
-                data = store.get(tag);
-                if (data == null) {
-                    data = new long[mSampleSize + 1];
-                    store.put(tag, data);
-                    data[mSampleSize] = 0;
-                }
-            }
-        }
-        return data;
-    }
-}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 02135bc..363a1bf 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -50,7 +50,7 @@
   *      }
   *  }</pre>
   */
-public class Looper {
+public final class Looper {
     private static final String TAG = "Looper";
 
     // sThreadLocal.get() will return null unless you've called prepare().
@@ -192,6 +192,14 @@
     }
 
     /**
+     * Returns true if the current thread is this looper's thread.
+     * @hide
+     */
+    public boolean isCurrentThread() {
+        return Thread.currentThread() == mThread;
+    }
+
+    /**
      * Quits the looper.
      *
      * Causes the {@link #loop} method to terminate as soon as possible.
@@ -223,7 +231,7 @@
      *
      * @hide
      */
-    public final int postSyncBarrier() {
+    public int postSyncBarrier() {
         return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
     }
 
@@ -238,7 +246,7 @@
      *
      * @hide
      */
-    public final void removeSyncBarrier(int token) {
+    public void removeSyncBarrier(int token) {
         mQueue.removeSyncBarrier(token);
     }
 
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 222578a..e0d40c9 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -29,7 +29,7 @@
  * <p>You can retrieve the MessageQueue for the current thread with
  * {@link Looper#myQueue() Looper.myQueue()}.
  */
-public class MessageQueue {
+public final class MessageQueue {
     // True if the message queue can be quit.
     private final boolean mQuitAllowed;
 
@@ -78,7 +78,7 @@
      * 
      * @param handler The IdleHandler to be added.
      */
-    public final void addIdleHandler(IdleHandler handler) {
+    public void addIdleHandler(IdleHandler handler) {
         if (handler == null) {
             throw new NullPointerException("Can't add a null IdleHandler");
         }
@@ -94,7 +94,7 @@
      * 
      * @param handler The IdleHandler to be removed.
      */
-    public final void removeIdleHandler(IdleHandler handler) {
+    public void removeIdleHandler(IdleHandler handler) {
         synchronized (this) {
             mIdleHandlers.remove(handler);
         }
@@ -121,7 +121,7 @@
         }
     }
 
-    final Message next() {
+    Message next() {
         int pendingIdleHandlerCount = -1; // -1 only during first iteration
         int nextPollTimeoutMillis = 0;
 
@@ -218,7 +218,7 @@
         }
     }
 
-    final void quit() {
+    void quit() {
         if (!mQuitAllowed) {
             throw new RuntimeException("Main thread not allowed to quit.");
         }
@@ -232,7 +232,7 @@
         nativeWake(mPtr);
     }
 
-    final int enqueueSyncBarrier(long when) {
+    int enqueueSyncBarrier(long when) {
         // Enqueue a new sync barrier token.
         // We don't need to wake the queue because the purpose of a barrier is to stall it.
         synchronized (this) {
@@ -259,7 +259,7 @@
         }
     }
 
-    final void removeSyncBarrier(int token) {
+    void removeSyncBarrier(int token) {
         // Remove a sync barrier token from the queue.
         // If the queue is no longer stalled by a barrier then wake it.
         final boolean needWake;
@@ -288,7 +288,7 @@
         }
     }
 
-    final boolean enqueueMessage(Message msg, long when) {
+    boolean enqueueMessage(Message msg, long when) {
         if (msg.isInUse()) {
             throw new AndroidRuntimeException(msg + " This message is already in use.");
         }
@@ -338,7 +338,7 @@
         return true;
     }
 
-    final boolean hasMessages(Handler h, int what, Object object) {
+    boolean hasMessages(Handler h, int what, Object object) {
         if (h == null) {
             return false;
         }
@@ -355,7 +355,7 @@
         }
     }
 
-    final boolean hasMessages(Handler h, Runnable r, Object object) {
+    boolean hasMessages(Handler h, Runnable r, Object object) {
         if (h == null) {
             return false;
         }
@@ -372,7 +372,7 @@
         }
     }
 
-    final void removeMessages(Handler h, int what, Object object) {
+    void removeMessages(Handler h, int what, Object object) {
         if (h == null) {
             return;
         }
@@ -406,7 +406,7 @@
         }
     }
 
-    final void removeMessages(Handler h, Runnable r, Object object) {
+    void removeMessages(Handler h, Runnable r, Object object) {
         if (h == null || r == null) {
             return;
         }
@@ -440,7 +440,7 @@
         }
     }
 
-    final void removeCallbacksAndMessages(Handler h, Object object) {
+    void removeCallbacksAndMessages(Handler h, Object object) {
         if (h == null) {
             return;
         }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index facab4c..476b4ea 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -166,11 +166,6 @@
     public static final int LAST_SHARED_APPLICATION_GID = 59999;
 
     /**
-     * Defines a secondary group id for access to the bluetooth hardware.
-     */
-    public static final int BLUETOOTH_GID = 2000;
-
-    /**
      * Standard priority of application threads.
      * Use with {@link #setThreadPriority(int)} and
      * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f682abe..3267939 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -203,10 +203,15 @@
      */
     public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000;  // for VmPolicy
 
+    /**
+     * @hide
+     */
+    private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000;  // for VmPolicy
+
     private static final int ALL_VM_DETECT_BITS =
             DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
             DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
-            DETECT_VM_REGISTRATION_LEAKS;
+            DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE;
 
     /**
      * @hide
@@ -628,7 +633,8 @@
              */
             public Builder detectAll() {
                 return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
-                        | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS);
+                        | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
+                        | DETECT_VM_FILE_URI_EXPOSURE);
             }
 
             /**
@@ -666,6 +672,16 @@
             }
 
             /**
+             * Detect when a {@code file://} {@link android.net.Uri} is exposed beyond this
+             * app. The receiving app may not have access to the sent path.
+             * Instead, when sharing files between apps, {@code content://}
+             * should be used with permission grants.
+             */
+            public Builder detectFileUriExposure() {
+                return enable(DETECT_VM_FILE_URI_EXPOSURE);
+            }
+
+            /**
              * Crashes the whole process on violation.  This penalty runs at
              * the end of all enabled penalties so yo you'll still get
              * your logging or other violations before the process dies.
@@ -1524,6 +1540,13 @@
     /**
      * @hide
      */
+    public static boolean vmFileUriExposureEnabled() {
+        return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
+    }
+
+    /**
+     * @hide
+     */
     public static void onSqliteObjectLeaked(String message, Throwable originStack) {
         onVmPolicyViolation(message, originStack);
     }
@@ -1549,6 +1572,14 @@
         onVmPolicyViolation(null, originStack);
     }
 
+    /**
+     * @hide
+     */
+    public static void onFileUriExposed(String location) {
+        final String message = "file:// Uri exposed through " + location;
+        onVmPolicyViolation(message, new Throwable(message));
+    }
+
     // Map from VM violation fingerprint to uptime millis.
     private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
 
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index c9adf45..729c64b 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -138,8 +138,6 @@
 
     /**
      * Returns milliseconds since boot, not counting time spent in deep sleep.
-     * <b>Note:</b> This value may get reset occasionally (before it would
-     * otherwise wrap around).
      *
      * @return milliseconds of non-sleep uptime since boot.
      */
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 27ed6b6..310b12c 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -19,41 +19,55 @@
 import android.util.Log;
 
 /**
- * Writes trace events to the kernel trace buffer.  These trace events can be
- * collected using the "atrace" program for offline analysis.
+ * Writes trace events to the system trace buffer.  These trace events can be
+ * collected and visualized using the Systrace tool.
  *
  * This tracing mechanism is independent of the method tracing mechanism
  * offered by {@link Debug#startMethodTracing}.  In particular, it enables
- * tracing of events that occur across processes.
+ * tracing of events that occur across multiple processes.
  *
  * @hide
  */
 public final class Trace {
+    /*
+     * Writes trace events to the kernel trace buffer.  These trace events can be
+     * collected using the "atrace" program for offline analysis.
+     */
+
     private static final String TAG = "Trace";
 
     // These tags must be kept in sync with system/core/include/cutils/trace.h.
+    /** @hide */
     public static final long TRACE_TAG_NEVER = 0;
+    /** @hide */
     public static final long TRACE_TAG_ALWAYS = 1L << 0;
+    /** @hide */
     public static final long TRACE_TAG_GRAPHICS = 1L << 1;
+    /** @hide */
     public static final long TRACE_TAG_INPUT = 1L << 2;
+    /** @hide */
     public static final long TRACE_TAG_VIEW = 1L << 3;
+    /** @hide */
     public static final long TRACE_TAG_WEBVIEW = 1L << 4;
+    /** @hide */
     public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5;
+    /** @hide */
     public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6;
+    /** @hide */
     public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7;
+    /** @hide */
     public static final long TRACE_TAG_AUDIO = 1L << 8;
+    /** @hide */
     public static final long TRACE_TAG_VIDEO = 1L << 9;
+    /** @hide */
     public static final long TRACE_TAG_CAMERA = 1L << 10;
+    /** @hide */
     public static final long TRACE_TAG_HAL = 1L << 11;
+    /** @hide */
+    public static final long TRACE_TAG_APP = 1L << 12;
+
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
-
-    public static final int TRACE_FLAGS_START_BIT = 1;
-    public static final String[] TRACE_TAGS = {
-        "Graphics", "Input", "View", "WebView", "Window Manager",
-        "Activity Manager", "Sync Manager", "Audio", "Video", "Camera", "HAL",
-    };
-
-    public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags";
+    private static final int MAX_SECTION_NAME_LEN = 127;
 
     // Must be volatile to avoid word tearing.
     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
@@ -62,6 +76,7 @@
     private static native void nativeTraceCounter(long tag, String name, int value);
     private static native void nativeTraceBegin(long tag, String name);
     private static native void nativeTraceEnd(long tag);
+    private static native void nativeSetAppTracingAllowed(boolean allowed);
 
     static {
         // We configure two separate change callbacks, one in Trace.cpp and one here.  The
@@ -111,6 +126,8 @@
      *
      * @param traceTag The trace tag to check.
      * @return True if the trace tag is valid.
+     *
+     * @hide
      */
     public static boolean isTagEnabled(long traceTag) {
         long tags = sEnabledTags;
@@ -126,6 +143,8 @@
      * @param traceTag The trace tag.
      * @param counterName The counter name to appear in the trace.
      * @param counterValue The counter value.
+     *
+     * @hide
      */
     public static void traceCounter(long traceTag, String counterName, int counterValue) {
         if (isTagEnabled(traceTag)) {
@@ -134,11 +153,28 @@
     }
 
     /**
-     * Writes a trace message to indicate that a given method has begun.
-     * Must be followed by a call to {@link #traceEnd} using the same tag.
+     * Set whether application tracing is allowed for this process.  This is intended to be set
+     * once at application start-up time based on whether the application is debuggable.
+     *
+     * @hide
+     */
+    public static void setAppTracingAllowed(boolean allowed) {
+        nativeSetAppTracingAllowed(allowed);
+
+        // Setting whether app tracing is allowed 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.
      *
      * @param traceTag The trace tag.
      * @param methodName The method name to appear in the trace.
+     *
+     * @hide
      */
     public static void traceBegin(long traceTag, String methodName) {
         if (isTagEnabled(traceTag)) {
@@ -151,10 +187,48 @@
      * Must be called exactly once for each call to {@link #traceBegin} using the same tag.
      *
      * @param traceTag The trace tag.
+     *
+     * @hide
      */
     public static void traceEnd(long traceTag) {
         if (isTagEnabled(traceTag)) {
             nativeTraceEnd(traceTag);
         }
     }
+
+    /**
+     * Writes a trace message to indicate that a given section of code has begun. This call must
+     * be followed by a corresponding call to {@link #traceEnd()} on the same thread.
+     *
+     * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
+     * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
+     * these characters they will be replaced with a space character in the trace.
+     *
+     * @param sectionName The name of the code section to appear in the trace.  This may be at
+     * most 127 Unicode code units long.
+     *
+     * @hide
+     */
+    public static void traceBegin(String sectionName) {
+        if (isTagEnabled(TRACE_TAG_APP)) {
+            if (sectionName.length() > MAX_SECTION_NAME_LEN) {
+                throw new IllegalArgumentException("sectionName is too long");
+            }
+            nativeTraceBegin(TRACE_TAG_APP, sectionName);
+        }
+    }
+
+    /**
+     * Writes a trace message to indicate that a given section of code has ended. This call must
+     * be preceeded by a corresponding call to {@link #traceBegin(String)}. Calling this method
+     * will mark the end of the most recently begun section of code, so care must be taken to
+     * ensure that traceBegin / traceEnd pairs are properly nested and called from the same thread.
+     *
+     * @hide
+     */
+    public static void traceEnd() {
+        if (isTagEnabled(TRACE_TAG_APP)) {
+            nativeTraceEnd(TRACE_TAG_APP);
+        }
+    }
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 51e3e7c..b9b8f08 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -17,6 +17,7 @@
 
 import android.app.ActivityManagerNative;
 import android.content.Context;
+import android.content.RestrictionEntry;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -36,48 +37,98 @@
     private final Context mContext;
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to add or remove accounts.
+     * Key for user restrictions. Specifies if a user is disallowed from adding and removing
+     * accounts.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_MODIFY_ACCOUNTS = "modify_accounts";
+    public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to change Wi-Fi access points.
+     * Key for user restrictions. Specifies if a user is disallowed from changing Wi-Fi
+     * access points.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_CONFIG_WIFI = "config_wifi";
+    public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to install applications.
+     * Key for user restrictions. Specifies if a user is disallowed from installing applications.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_INSTALL_APPS = "install_apps";
+    public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
 
     /**
-     * @hide
-     * Key for user restrictions. Specifies if a user is allowed to uninstall applications.
+     * Key for user restrictions. Specifies if a user is disallowed from uninstalling applications.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_UNINSTALL_APPS = "uninstall_apps";
+    public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
 
-    /** @hide *
-     * Key for user restrictions. Specifies if a user is allowed to toggle location sharing.
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from toggling location sharing.
+     * The default value is <code>false</code>.
+     * <p/>
      * Type: Boolean
      * @see #setUserRestrictions(Bundle)
      * @see #getUserRestrictions()
      */
-    public static final String ALLOW_CONFIG_LOCATION_ACCESS = "config_location_access";
+
+    public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from enabling the
+     * "Unknown Sources" setting, that allows installation of apps from unknown sources.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from configuring bluetooth.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
+
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from transferring files over
+     * USB. The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+
+    private static UserManager sInstance = null;
+
+    public synchronized static UserManager get(Context context) {
+        if (sInstance == null) {
+            sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        }
+        return sInstance;
+    }
 
     /** @hide */
     public UserManager(Context context, IUserManager service) {
@@ -121,12 +172,27 @@
    /**
      * Used to determine whether the user making this call is subject to
      * teleportations.
-     * @return whether the user making this call is a goat 
+     * @return whether the user making this call is a goat
      */
     public boolean isUserAGoat() {
         return false;
     }
- 
+
+    /**
+     * Used to check if the user making this call is a restricted user. Restricted users may have
+     * application restrictions imposed on them. All apps should default to the most restrictive
+     * version, unless they have specific restrictions available through a call to
+     * {@link Context#getApplicationRestrictions()}.
+     */
+    public boolean isUserRestricted() {
+        try {
+            return mService.isRestricted();
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not check if user restricted ", re);
+            return false;
+        }
+    }
+
     /**
      * Return whether the given user is actively running.  This means that
      * the user is in the "started" state, not "stopped" -- it is currently
@@ -176,12 +242,19 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Returns the user-wide restrictions imposed on this user.
+     * @return a Bundle containing all the restrictions.
+     */
     public Bundle getUserRestrictions() {
         return getUserRestrictions(Process.myUserHandle());
     }
 
-    /** @hide */
+    /**
+     * Returns the user-wide restrictions imposed on the user specified by <code>userHandle</code>.
+     * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+     * @return a Bundle containing all the restrictions.
+     */
     public Bundle getUserRestrictions(UserHandle userHandle) {
         try {
             return mService.getUserRestrictions(userHandle.getIdentifier());
@@ -191,12 +264,21 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Sets all the user-wide restrictions for this user.
+     * Requires the MANAGE_USERS permission.
+     * @param restrictions the Bundle containing all the restrictions.
+     */
     public void setUserRestrictions(Bundle restrictions) {
         setUserRestrictions(restrictions, Process.myUserHandle());
     }
 
-    /** @hide */
+    /**
+     * Sets all the user-wide restrictions for the specified user.
+     * Requires the MANAGE_USERS permission.
+     * @param restrictions the Bundle containing all the restrictions.
+     * @param userHandle the UserHandle of the user for whom to set the restrictions.
+     */
     public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
         try {
             mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
@@ -205,7 +287,26 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Sets the value of a specific restriction.
+     * Requires the MANAGE_USERS permission.
+     * @param key the key of the restriction
+     * @param value the value for the restriction
+     */
+    public void setUserRestriction(String key, boolean value) {
+        Bundle bundle = getUserRestrictions();
+        bundle.putBoolean(key, value);
+        setUserRestrictions(bundle);
+    }
+
+    /**
+     * @hide
+     * Sets the value of a specific restriction on a specific user.
+     * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param key the key of the restriction
+     * @param value the value for the restriction
+     * @param userHandle the user whose restriction is to be changed.
+     */
     public void setUserRestriction(String key, boolean value, UserHandle userHandle) {
         Bundle bundle = getUserRestrictions(userHandle);
         bundle.putBoolean(key, value);
@@ -213,6 +314,16 @@
     }
 
     /**
+     * @hide
+     * Returns whether the current user has been disallowed from performing certain actions
+     * or setting certain settings.
+     * @param restrictionKey the string key representing the restriction
+     */
+    public boolean hasUserRestriction(String restrictionKey) {
+        return getUserRestrictions().getBoolean(restrictionKey, false);
+    }
+
+    /**
      * Return the serial number for a user.  This is a device-unique
      * number assigned to that user; if the user is deleted and then a new
      * user created, the new users will not be given the same serial number.
@@ -406,7 +517,7 @@
      * Returns the maximum number of users that can be created on this device. A return value
      * of 1 means that it is a single user device.
      * @hide
-     * @return a value greater than or equal to 1 
+     * @return a value greater than or equal to 1
      */
     public static int getMaxSupportedUsers() {
         // Don't allow multiple users on certain builds
@@ -449,11 +560,28 @@
         return -1;
     }
 
+
     /**
-     * Returns whether the current user is allow to toggle location sharing settings.
      * @hide
      */
-    public boolean isLocationSharingToggleAllowed() {
-        return getUserRestrictions().getBoolean(ALLOW_CONFIG_LOCATION_ACCESS);
+    public List<RestrictionEntry> getApplicationRestrictions(String packageName, UserHandle user) {
+        try {
+            return mService.getApplicationRestrictions(packageName, user.getIdentifier());
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier());
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
+    public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+            UserHandle user) {
+        try {
+            mService.setApplicationRestrictions(packageName, entries, user.getIdentifier());
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
+        }
     }
 }
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 2dd27f8..25af209 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -106,16 +106,13 @@
      * {@link Activity#RESULT_OK} or {@link Activity#RESULT_CANCELED} to
      * acknowledge whether the action was handled or not.
      *
-     * The custom app should have an intent-filter like the following
+     * The custom app should have an intent filter like the following:
      * <pre>
-     * {@code
-     * <intent-filter>
-     *    <action android:name="android.provider.calendar.action.HANDLE_CUSTOM_EVENT" />
-     *    <category android:name="android.intent.category.DEFAULT" />
-     *    <data android:mimeType="vnd.android.cursor.item/event" />
-     * </intent-filter>
-     * }
-     * </pre>
+     * &lt;intent-filter&gt;
+     *    &lt;action android:name="android.provider.calendar.action.HANDLE_CUSTOM_EVENT" /&gt;
+     *    &lt;category android:name="android.intent.category.DEFAULT" /&gt;
+     *    &lt;data android:mimeType="vnd.android.cursor.item/event" /&gt;
+     * &lt;/intent-filter&gt;</pre>
      * <p>
      * Input: {@link Intent#getData} has the event URI. The extra
      * {@link #EXTRA_EVENT_BEGIN_TIME} has the start time of the instance. The
@@ -123,7 +120,7 @@
      * {@link EventsColumns#CUSTOM_APP_URI}.
      * <p>
      * Output: {@link Activity#RESULT_OK} if this was handled; otherwise
-     * {@link Activity#RESULT_CANCELED}
+     * {@link Activity#RESULT_CANCELED}.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_HANDLE_CUSTOM_EVENT =
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8f54a38..c41c35e 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -35,9 +35,7 @@
 import android.database.DatabaseUtils;
 import android.graphics.Rect;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Pair;
@@ -939,6 +937,15 @@
          * its row id changed as a result of a sync or aggregation.
          */
         public static final String LOOKUP_KEY = "lookup";
+
+        /**
+         * Timestamp (milliseconds since epoch) of when this contact was last updated.  This
+         * includes updates to all data associated with this contact including raw contacts.  Any
+         * modification (including deletes and inserts) of underlying contact data are also
+         * reflected in this timestamp.
+         */
+        public static final String CONTACT_LAST_UPDATED_TIMESTAMP =
+                "contact_last_updated_timestamp";
     }
 
     /**
@@ -1359,7 +1366,7 @@
      * status definitions. Automatically computed as the highest presence of all
      * constituent raw contacts. The provider may choose not to store this value
      * in persistent storage. The expectation is that presence status will be
-     * updated on a regular basic.</td>
+     * updated on a regular basis.</td>
      * </tr>
      * <tr>
      * <td>String</td>
@@ -2113,6 +2120,56 @@
         return id >= Profile.MIN_ID;
     }
 
+    protected interface DeletedContactsColumns {
+
+        /**
+         * A reference to the {@link ContactsContract.Contacts#_ID} that was deleted.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String CONTACT_ID = "contact_id";
+
+        /**
+         * Time (milliseconds since epoch) that the contact was deleted.
+         */
+        public static final String CONTACT_DELETED_TIMESTAMP = "contact_deleted_timestamp";
+    }
+
+    /**
+     * Constants for the deleted contact table.  This table holds a log of deleted contacts.
+     * <p>
+     * Log older than {@link #DAYS_KEPT_MILLISECONDS} may be deleted.
+     */
+    public static final class DeletedContacts implements DeletedContactsColumns {
+
+        /**
+         * This utility class cannot be instantiated
+         */
+        private DeletedContacts() {
+        }
+
+        /**
+         * The content:// style URI for this table, which requests a directory of raw contact rows
+         * matching the selection criteria.
+         */
+        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
+                "deleted_contacts");
+
+        /**
+         * Number of days that the delete log will be kept.  After this time, delete records may be
+         * deleted.
+         *
+         * @hide
+         */
+        private static final int DAYS_KEPT = 30;
+
+        /**
+         * Milliseconds that the delete log will be kept.  After this time, delete records may be
+         * deleted.
+         */
+        public static final long DAYS_KEPT_MILLISECONDS = 1000L * 60L * 60L * 24L * (long)DAYS_KEPT;
+    }
+
+
     protected interface RawContactsColumns {
         /**
          * A reference to the {@link ContactsContract.Contacts#_ID} that this
@@ -3793,13 +3850,24 @@
     }
 
     /**
+     * Columns in the Data_Usage_Stat table
+     */
+    protected interface DataUsageStatColumns {
+        /** The last time (in milliseconds) this {@link Data} was used. */
+        public static final String LAST_TIME_USED = "last_time_used";
+
+        /** The number of times the referenced {@link Data} has been used. */
+        public static final String TIMES_USED = "times_used";
+    }
+
+    /**
      * Combines all columns returned by {@link ContactsContract.Data} table queries.
      *
      * @see ContactsContract.Data
      */
     protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns,
             RawContactsColumns, ContactsColumns, ContactNameColumns, ContactOptionsColumns,
-            ContactStatusColumns {
+            ContactStatusColumns, DataUsageStatColumns {
     }
 
     /**
@@ -4131,7 +4199,7 @@
      * all IM rows. See {@link StatusUpdates} for individual status definitions.
      * The provider may choose not to store this value
      * in persistent storage. The expectation is that presence status will be
-     * updated on a regular basic.
+     * updated on a regular basis.
      * </td>
      * </tr>
      * <tr>
@@ -4325,6 +4393,13 @@
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
 
         /**
+         * A boolean parameter for {@link Data#CONTENT_URI}.
+         * This specifies whether or not the returned data items should be filtered to show
+         * data items belonging to visible contacts only.
+         */
+        public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
+
+        /**
          * The MIME type of the results from {@link #CONTENT_URI}.
          */
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/data";
@@ -6833,6 +6908,38 @@
             public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI,
                     "filter");
         }
+
+        /**
+         * A special class of data items, used to refer to types of data that can be used to attempt
+         * to start communicating with a person ({@link Phone} and {@link Email}). Note that this
+         * is NOT a separate data kind.
+         *
+         * This URI allows the ContactsProvider to return a unified result for data items that users
+         * can use to initiate communications with another contact. {@link Phone} and {@link Email}
+         * are the current data types in this category.
+         */
+        public static final class Contactables implements DataColumnsWithJoins, CommonColumns {
+            /**
+             * The content:// style URI for these data items, which requests a directory of data
+             * rows matching the selection criteria.
+             */
+            public static final Uri CONTENT_URI = Uri.withAppendedPath(Data.CONTENT_URI,
+                    "contactables");
+
+            /**
+             * The content:// style URI for these data items, which allows for a query parameter to
+             * be appended onto the end to filter for data items matching the query.
+             */
+            public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(
+                    Contactables.CONTENT_URI, "filter");
+
+            /**
+             * A boolean parameter for {@link Data#CONTENT_URI}.
+             * This specifies whether or not the returned data items should be filtered to show
+             * data items belonging to visible contacts only.
+             */
+            public static final String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
+        }
     }
 
     /**
@@ -7859,6 +7966,13 @@
                 "android.provider.Contacts.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED";
 
         /**
+         * This is the intent that is fired when the contacts database is created. <p> The
+         * READ_CONTACT permission is required to receive these broadcasts.
+         */
+        public static final String CONTACTS_DATABASE_CREATED =
+                "android.provider.Contacts.DATABASE_CREATED";
+
+        /**
          * Starts an Activity that lets the user pick a contact to attach an image to.
          * After picking the contact it launches the image cropper in face detection mode.
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 266d0d3..88ee414 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -655,6 +655,22 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
 
+    /**
+     * Activity Action: Show Notification listener settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @see android.service.notification.NotificationListenerService
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS
+            = "android.settings.NOTIFICATION_LISTENER_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -4039,6 +4055,14 @@
         public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
 
         /**
+         * Name of a package that the current user has explicitly allowed to see all of that
+         * user's notifications.
+         *
+         * @hide
+         */
+        public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -4403,6 +4427,14 @@
        public static final String DATA_ROAMING = "data_roaming";
 
        /**
+        * The value passed to a Mobile DataConnection via bringUp which defines the
+        * number of retries to preform when setting up the initial connection. The default
+        * value defined in DataConnectionTrackerBase#DEFAULT_MDC_INITIAL_RETRY is currently 1.
+        * @hide
+        */
+       public static final String MDC_INITIAL_MAX_RETRY = "mdc_initial_max_retry";
+
+       /**
         * Whether user has enabled development settings.
         */
        public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
@@ -4784,6 +4816,21 @@
        public static final String WIFI_ON = "wifi_on";
 
        /**
+        * Setting to allow scans to be enabled even wifi is turned off for connectivity.
+        * @hide
+        */
+       public static final String WIFI_SCAN_ALWAYS_AVAILABLE =
+                "wifi_scan_always_enabled";
+
+       /**
+        * Setting to indicate whether the user should be notified that scans are still
+        * available when Wi-Fi is turned off
+        * @hide
+        */
+       public static final String WIFI_NOTIFY_SCAN_ALWAYS_AVAILABLE =
+                "wifi_notify_scan_always_enabled";
+
+       /**
         * Used to save the Wifi_ON state prior to tethering.
         * This state will be checked to restore Wifi after
         * the user turns off tethering.
@@ -5317,6 +5364,76 @@
         public static final String AUDIO_SAFE_VOLUME_STATE = "audio_safe_volume_state";
 
         /**
+         * URL for tzinfo (time zone) updates
+         * @hide
+         */
+        public static final String TZINFO_UPDATE_CONTENT_URL = "tzinfo_content_url";
+
+        /**
+         * URL for tzinfo (time zone) update metadata
+         * @hide
+         */
+        public static final String TZINFO_UPDATE_METADATA_URL = "tzinfo_metadata_url";
+
+        /**
+         * URL for selinux (mandatory access control) updates
+         * @hide
+         */
+        public static final String SELINUX_UPDATE_CONTENT_URL = "selinux_content_url";
+
+        /**
+         * URL for selinux (mandatory access control) update metadata
+         * @hide
+         */
+        public static final String SELINUX_UPDATE_METADATA_URL = "selinux_metadata_url";
+
+        /**
+         * URL for sms short code updates
+         * @hide
+         */
+        public static final String SMS_SHORT_CODES_UPDATE_CONTENT_URL =
+                "sms_short_codes_content_url";
+
+        /**
+         * URL for sms short code update metadata
+         * @hide
+         */
+        public static final String SMS_SHORT_CODES_UPDATE_METADATA_URL =
+                "sms_short_codes_metadata_url";
+
+        /**
+         * URL for cert pinlist updates
+         * @hide
+         */
+        public static final String CERT_PIN_UPDATE_CONTENT_URL = "cert_pin_content_url";
+
+        /**
+         * URL for cert pinlist updates
+         * @hide
+         */
+        public static final String CERT_PIN_UPDATE_METADATA_URL = "cert_pin_metadata_url";
+
+        /**
+         * URL for intent firewall updates
+         * @hide
+         */
+        public static final String INTENT_FIREWALL_UPDATE_CONTENT_URL =
+                "intent_firewall_content_url";
+
+        /**
+         * URL for intent firewall update metadata
+         * @hide
+         */
+        public static final String INTENT_FIREWALL_UPDATE_METADATA_URL =
+                "intent_firewall_metadata_url";
+
+        /**
+         * SELinux enforcement status. If 0, permissive; if 1, enforcing.
+         * @hide
+         */
+        public static final String SELINUX_STATUS = "selinux_status";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
@@ -5345,6 +5462,7 @@
             WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
             WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
             WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+            WIFI_SCAN_ALWAYS_AVAILABLE,
             WIFI_NUM_OPEN_NETWORKS_KEPT,
             EMERGENCY_TONE,
             CALL_AUTO_RETRY,
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index 651693a..e1cc90e 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -148,6 +148,10 @@
                     for (int i = 0; i < size; i++) {
                         _result[i] = _reply.readString();
                     }
+                    int _ret = _reply.readInt();
+                    if (_ret != 1) {
+                        return null;
+                    }
                 } finally {
                     _reply.recycle();
                     _data.recycle();
@@ -401,6 +405,63 @@
                 }
                 return _result;
             }
+
+            @Override
+            public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(srcKey);
+                    _data.writeInt(srcUid);
+                    _data.writeString(destKey);
+                    _data.writeInt(destUid);
+                    mRemote.transact(Stub.TRANSACTION_duplicate, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            @Override
+            public int is_hardware_backed() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            @Override
+            public int clear_uid(long uid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                int _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeLong(uid);
+                    mRemote.transact(Stub.TRANSACTION_clear_uid, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readInt();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
         }
 
         private static final String DESCRIPTOR = "android.security.keystore";
@@ -425,6 +486,9 @@
         static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
         static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
         static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
+        static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
+        static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
+        static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22;
 
         /**
          * Cast an IBinder object into an IKeystoreService interface, generating
@@ -509,4 +573,11 @@
     public int ungrant(String name, int granteeUid) throws RemoteException;
 
     public long getmtime(String name) throws RemoteException;
+
+    public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
+            throws RemoteException;
+
+    public int is_hardware_backed() throws RemoteException;
+
+    public int clear_uid(long uid) throws RemoteException;
 }
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
new file mode 100644
index 0000000..425fdc1
--- /dev/null
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -0,0 +1,26 @@
+/**
+ * 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.service.notification;
+
+import android.service.notification.StatusBarNotification;
+
+/** @hide */
+oneway interface INotificationListener
+{
+    void onNotificationPosted(in StatusBarNotification notification);
+    void onNotificationRemoved(in StatusBarNotification notification);
+}
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
new file mode 100644
index 0000000..86bab2a
--- /dev/null
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -0,0 +1,138 @@
+/*
+ * 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.service.notification;
+
+import android.annotation.SdkConstant;
+import android.app.INotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+public abstract class NotificationListenerService extends Service {
+    // TAG = "NotificationListenerService[MySubclass]"
+    private final String TAG = NotificationListenerService.class.getSimpleName()
+            + "[" + getClass().getSimpleName() + "]";
+
+    private INotificationListenerWrapper mWrapper = null;
+
+    private INotificationManager mNoMan;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE
+            = "android.service.notification.NotificationListenerService";
+
+    /**
+     * Implement this method to learn about new notifications as they are posted by apps.
+     *
+     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
+     *            object as well as its identifying information (tag and id) and source
+     *            (package name).
+     */
+    public abstract void onNotificationPosted(StatusBarNotification sbn);
+
+    /**
+     * Implement this method to learn when notifications are removed.
+     * <P>
+     * This might occur because the user has dismissed the notification using system UI (or another
+     * notification listener) or because the app has withdrawn the notification.
+     *
+     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
+     *            object as well as its identifying information (tag and id) and source
+     *            (package name).
+     */
+    public abstract void onNotificationRemoved(StatusBarNotification sbn);
+
+    private final INotificationManager getNotificationInterface() {
+        if (mNoMan == null) {
+            mNoMan = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+        }
+        return mNoMan;
+    }
+
+    /**
+     * Inform the notification manager about dismissal of a single notification.
+     * <p>
+     * Use this if your listener has a user interface that allows the user to dismiss individual
+     * notifications, similar to the behavior of Android's status bar and notification panel.
+     * It should be called after the user dismisses a single notification using your UI;
+     * upon being informed, the notification manager will actually remove the notification
+     * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback.
+     * <P>
+     * <b>Note:</b> If your listener allows the user to fire a notification's
+     * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call
+     * this method at that time <i>if</i> the Notification in question has the
+     * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set.
+     *
+     * @param pkg Package of the notifying app.
+     * @param tag Tag of the notification as specified by the notifying app in
+     *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
+     * @param id  ID of the notification as specified by the notifying app in
+     *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
+     */
+    public final void clearNotification(String pkg, String tag, int id) {
+        try {
+            getNotificationInterface().clearNotificationFromListener(mWrapper, pkg, tag, id);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    /**
+     * Inform the notification manager about dismissal of all notifications.
+     * <p>
+     * Use this if your listener has a user interface that allows the user to dismiss all
+     * notifications, similar to the behavior of Android's status bar and notification panel.
+     * It should be called after the user invokes the "dismiss all" function of your UI;
+     * upon being informed, the notification manager will actually remove all active notifications
+     * and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks.
+     *
+     * {@see #clearNotification(String, String, int)}
+     */
+    public final void clearAllNotifications() {
+        try {
+            getNotificationInterface().clearAllNotificationsFromListener(mWrapper);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mWrapper == null) {
+            mWrapper = new INotificationListenerWrapper();
+        }
+        return mWrapper;
+    }
+
+    private class INotificationListenerWrapper extends INotificationListener.Stub {
+        @Override
+        public void onNotificationPosted(StatusBarNotification sbn) {
+            NotificationListenerService.this.onNotificationPosted(sbn);
+        }
+        @Override
+        public void onNotificationRemoved(StatusBarNotification sbn) {
+            NotificationListenerService.this.onNotificationRemoved(sbn);
+        }
+    }
+}
diff --git a/core/java/android/service/notification/StatusBarNotification.aidl b/core/java/android/service/notification/StatusBarNotification.aidl
new file mode 100644
index 0000000..ba81972
--- /dev/null
+++ b/core/java/android/service/notification/StatusBarNotification.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+parcelable StatusBarNotification;
+
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
new file mode 100644
index 0000000..ef5f8c4
--- /dev/null
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2008 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.service.notification;
+
+import android.app.Notification;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+
+/**
+ * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
+ * the status bar and any {@link android.service.notification.NotificationListenerService}s.
+ */
+public class StatusBarNotification implements Parcelable {
+    /** The package of the app that posted the notification. */
+    public final String pkg;
+    /** The id supplied to {@link android.app.NotificationManager#notify}. */
+    public final int id;
+    /** The tag supplied to {@link android.app.NotificationManager#notify}, or null if no tag
+     * was specified. */
+    public final String tag;
+
+    /** The notifying app's calling uid. @hide */
+    public final int uid;
+    /** The notifying app's base package. @hide */
+    public final String basePkg;
+    /** @hide */
+    public final int initialPid;
+    // TODO: make this field private and move callers to an accessor that
+    // ensures sourceUser is applied.
+
+    /** The {@link android.app.Notification} supplied to
+     * {@link android.app.NotificationManager#notify}. */
+    public final Notification notification;
+    /** The {@link android.os.UserHandle} for whom this notification is intended. */
+    public final UserHandle user;
+    /** The time (in {@link System#currentTimeMillis} time) the notification was posted,
+     * which may be different than {@link android.app.Notification#when}.
+     */
+    public final long postTime;
+
+    /** @hide */
+    public final int score;
+
+    /** This is temporarily needed for the JB MR1 PDK.
+     * @hide */
+    @Deprecated
+    public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
+            Notification notification) {
+        this(pkg, id, tag, uid, initialPid, score, notification, UserHandle.OWNER);
+    }
+
+    /** @hide */
+    public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
+            Notification notification, UserHandle user) {
+        this(pkg, null, id, tag, uid, initialPid, score, notification, user);
+    }
+
+    /** @hide */
+    public StatusBarNotification(String pkg, String basePkg, int id, String tag, int uid,
+            int initialPid, int score, Notification notification, UserHandle user) {
+        this(pkg, basePkg, id, tag, uid, initialPid, score, notification, user,
+                System.currentTimeMillis());
+    }
+
+    public StatusBarNotification(String pkg, String basePkg, int id, String tag, int uid,
+            int initialPid, int score, Notification notification, UserHandle user,
+            long postTime) {
+        if (pkg == null) throw new NullPointerException();
+        if (notification == null) throw new NullPointerException();
+
+        this.pkg = pkg;
+        this.basePkg = pkg;
+        this.id = id;
+        this.tag = tag;
+        this.uid = uid;
+        this.initialPid = initialPid;
+        this.score = score;
+        this.notification = notification;
+        this.user = user;
+        this.notification.setUser(user);
+
+        this.postTime = postTime;
+    }
+
+    public StatusBarNotification(Parcel in) {
+        this.pkg = in.readString();
+        this.basePkg = in.readString();
+        this.id = in.readInt();
+        if (in.readInt() != 0) {
+            this.tag = in.readString();
+        } else {
+            this.tag = null;
+        }
+        this.uid = in.readInt();
+        this.initialPid = in.readInt();
+        this.score = in.readInt();
+        this.notification = new Notification(in);
+        this.user = UserHandle.readFromParcel(in);
+        this.notification.setUser(this.user);
+        this.postTime = in.readLong();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(this.pkg);
+        out.writeString(this.basePkg);
+        out.writeInt(this.id);
+        if (this.tag != null) {
+            out.writeInt(1);
+            out.writeString(this.tag);
+        } else {
+            out.writeInt(0);
+        }
+        out.writeInt(this.uid);
+        out.writeInt(this.initialPid);
+        out.writeInt(this.score);
+        this.notification.writeToParcel(out, flags);
+        user.writeToParcel(out, flags);
+
+        out.writeLong(this.postTime);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<StatusBarNotification> CREATOR
+            = new Parcelable.Creator<StatusBarNotification>()
+    {
+        public StatusBarNotification createFromParcel(Parcel parcel)
+        {
+            return new StatusBarNotification(parcel);
+        }
+
+        public StatusBarNotification[] newArray(int size)
+        {
+            return new StatusBarNotification[size];
+        }
+    };
+
+    @Override
+    public StatusBarNotification clone() {
+        return new StatusBarNotification(this.pkg, this.basePkg,
+                this.id, this.tag, this.uid, this.initialPid,
+                this.score, this.notification.clone(), this.user, this.postTime);
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+                this.pkg, this.user, this.id, this.tag,
+                this.score, this.notification);
+    }
+
+    /** Convenience method to check the notification's flags for
+     * {@link Notification#FLAG_ONGOING_EVENT}.
+     */
+    public boolean isOngoing() {
+        return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
+    }
+
+    /** Convenience method to check the notification's flags for
+     * either {@link Notification#FLAG_ONGOING_EVENT} or
+     * {@link Notification#FLAG_NO_CLEAR}.
+     */
+    public boolean isClearable() {
+        return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
+                && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
+    }
+
+    /** Returns a userHandle for the instance of the app that posted this notification. */
+    public int getUserId() {
+        return this.user.getIdentifier();
+    }
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 71d8fb6..5db8168 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -762,7 +762,7 @@
             mWindowToken = wrapper.mWindowToken;
             mSurfaceHolder.setSizeFromLayout();
             mInitializing = true;
-            mSession = WindowManagerGlobal.getWindowSession(getMainLooper());
+            mSession = WindowManagerGlobal.getWindowSession();
             
             mWindow.setSession(mSession);
 
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 4379418..703dcff 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -810,9 +810,15 @@
                 return TextToSpeech.ERROR;
             }
 
+            // In test env, ParcelFileDescriptor instance may be EXACTLY the same
+            // one that is used by client. And it will be closed by a client, thus
+            // preventing us from writing anything to it.
+            final ParcelFileDescriptor sameFileDescriptor = ParcelFileDescriptor.adoptFd(
+                    fileDescriptor.detachFd());
+
             SpeechItem item = new SynthesisToFileOutputStreamSpeechItem(caller,
                     Binder.getCallingUid(), Binder.getCallingPid(), params, text,
-                    new ParcelFileDescriptor.AutoCloseOutputStream(fileDescriptor));
+                    new ParcelFileDescriptor.AutoCloseOutputStream(sameFileDescriptor));
             return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item);
         }
 
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 60545e5..d426d124 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -38,7 +38,7 @@
      * {@hide}
      */
     void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint p);
+            float x, float y, int flags, Paint p);
 
    /**
      * Just like {@link Paint#measureText}.
@@ -55,12 +55,12 @@
      * @hide
      */
     float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
-            float[] advances, int advancesIndex, Paint paint);
+            int flags, float[] advances, int advancesIndex, Paint paint);
 
     /**
      * Just like {@link Paint#getTextRunCursor}.
      * @hide
      */
-    int getTextRunCursor(int contextStart, int contextEnd, int offset,
+    int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
             int cursorOpt, Paint p);
 }
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 0c881a4..bd9310c1 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -159,15 +159,18 @@
         mPos = p + len;
 
         if (mEasy) {
-            return paint.getTextRunAdvances(mChars, p, len, p, len, mWidths, p);
+            int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
+                ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
+            return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
         }
 
         float totalAdvance = 0;
         int level = mLevels[p];
         for (int q = p, i = p + 1, e = p + len;; ++i) {
             if (i == e || mLevels[i] != level) {
+                int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
                 totalAdvance +=
-                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, mWidths, q);
+                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
                 if (i == e) {
                     break;
                 }
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 9e43671..8929930 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1130,20 +1130,20 @@
      * {@hide}
      */
     public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint p) {
+            float x, float y, int flags, Paint p) {
         checkRange("drawTextRun", start, end);
 
         int contextLen = contextEnd - contextStart;
         int len = end - start;
         if (contextEnd <= mGapStart) {
-            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, p);
+            c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p);
         } else if (contextStart >= mGapStart) {
             c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
-                    contextLen, x, y, p);
+                    contextLen, x, y, flags, p);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
-            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, p);
+            c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p);
             TextUtils.recycle(buf);
         }
     }
@@ -1200,7 +1200,7 @@
      * Don't call this yourself -- exists for Paint to use internally.
      * {@hide}
      */
-    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
+    public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
             float[] advances, int advancesPos, Paint p) {
 
         float ret;
@@ -1210,15 +1210,15 @@
 
         if (end <= mGapStart) {
             ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
-                    advances, advancesPos);
+                    flags, advances, advancesPos);
         } else if (start >= mGapStart) {
             ret = p.getTextRunAdvances(mText, start + mGapLength, len,
-                    contextStart + mGapLength, contextLen, advances, advancesPos);
+                    contextStart + mGapLength, contextLen, flags, advances, advancesPos);
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunAdvances(buf, start - contextStart, len,
-                    0, contextLen, advances, advancesPos);
+                    0, contextLen, flags, advances, advancesPos);
             TextUtils.recycle(buf);
         }
 
@@ -1241,7 +1241,7 @@
      *
      * @param contextStart the start index of the context
      * @param contextEnd the (non-inclusive) end index of the context
-     * @param flags reserved
+     * @param flags either DIRECTION_RTL or DIRECTION_LTR
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
      * CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@@ -1252,30 +1252,22 @@
      */
     @Deprecated
     public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
-                                int cursorOpt, Paint p) {
-        return getTextRunCursor(contextStart, contextEnd, offset, cursorOpt, p);
-    }
-
-    /**
-     * @hide
-     */
-    public int getTextRunCursor(int contextStart, int contextEnd, int offset,
-                                int cursorOpt, Paint p) {
+            int cursorOpt, Paint p) {
 
         int ret;
 
         int contextLen = contextEnd - contextStart;
         if (contextEnd <= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart, contextLen,
-                    offset, cursorOpt);
+                    flags, offset, cursorOpt);
         } else if (contextStart >= mGapStart) {
             ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
-                    offset + mGapLength, cursorOpt) - mGapLength;
+                    flags, offset + mGapLength, cursorOpt) - mGapLength;
         } else {
             char[] buf = TextUtils.obtain(contextLen);
             getChars(contextStart, contextEnd, buf, 0);
             ret = p.getTextRunCursor(buf, 0, contextLen,
-                    offset - contextStart, cursorOpt) + contextStart;
+                    flags, offset - contextStart, cursorOpt) + contextStart;
             TextUtils.recycle(buf);
         }
 
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 9051285..1291279 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -340,7 +340,7 @@
                         w += widths[j - paraStart];
                     }
 
-                    boolean isSpaceOrTab = c == CHAR_SPACE || c == CHAR_TAB;
+                    boolean isSpaceOrTab = c == CHAR_SPACE || c == CHAR_TAB || c == CHAR_ZWSP;
 
                     if (w <= width || isSpaceOrTab) {
                         fitWidth = w;
@@ -956,6 +956,7 @@
     private static final char CHAR_SPACE = ' ';
     private static final char CHAR_SLASH = '/';
     private static final char CHAR_HYPHEN = '-';
+    private static final char CHAR_ZWSP = '\u200B';
 
     private static final double EXTRA_ROUNDING = 0.5;
 
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index e34a0ef..1fecf81 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -664,13 +664,14 @@
             }
         }
 
+        int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
         int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
         if (mCharsValid) {
             return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
-                    offset, cursorOpt);
+                    flags, offset, cursorOpt);
         } else {
             return wp.getTextRunCursor(mText, mStart + spanStart,
-                    mStart + spanLimit, mStart + offset, cursorOpt) - mStart;
+                    mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
         }
     }
 
@@ -737,13 +738,15 @@
 
         int contextLen = contextEnd - contextStart;
         if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
+            int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
             if (mCharsValid) {
                 ret = wp.getTextRunAdvances(mChars, start, runLen,
-                        contextStart, contextLen, null, 0);
+                        contextStart, contextLen, flags, null, 0);
             } else {
                 int delta = mStart;
-                ret = wp.getTextRunAdvances(mText, delta + start, delta + end,
-                        delta + contextStart, delta + contextEnd, null, 0);
+                ret = wp.getTextRunAdvances(mText, delta + start,
+                        delta + end, delta + contextStart, delta + contextEnd,
+                        flags, null, 0);
             }
         }
 
@@ -783,7 +786,8 @@
                 wp.setAntiAlias(previousAntiAlias);
             }
 
-            drawTextRun(c, wp, start, end, contextStart, contextEnd, x, y + wp.baselineShift);
+            drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
+                    x, y + wp.baselineShift);
         }
 
         return runIsRtl ? -ret : ret;
@@ -966,21 +970,23 @@
      * @param end the end of the run
      * @param contextStart the start of context for the run
      * @param contextEnd the end of the context for the run
+     * @param runIsRtl true if the run is right-to-left
      * @param x the x position of the left edge of the run
      * @param y the baseline of the run
      */
     private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
-            int contextStart, int contextEnd, float x, int y) {
+            int contextStart, int contextEnd, boolean runIsRtl, float x, int y) {
 
+        int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
         if (mCharsValid) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start, count, contextStart, contextCount,
-                    x, y, wp);
+                    x, y, flags, wp);
         } else {
             int delta = mStart;
             c.drawTextRun(mText, delta + start, delta + end,
-                    delta + contextStart, delta + contextEnd, x, y, wp);
+                    delta + contextStart, delta + contextEnd, x, y, flags, wp);
         }
     }
 
diff --git a/core/java/android/text/bidi/BidiFormatter.java b/core/java/android/text/bidi/BidiFormatter.java
index 370cbf7..c5a77a6 100644
--- a/core/java/android/text/bidi/BidiFormatter.java
+++ b/core/java/android/text/bidi/BidiFormatter.java
@@ -172,9 +172,9 @@
      * A class for building a BidiFormatter with non-default options.
      */
     public static final class Builder {
-        private boolean isRtlContext;
-        private int flags;
-        private TextDirectionHeuristic textDirectionHeuristic;
+        private boolean mIsRtlContext;
+        private int mFlags;
+        private TextDirectionHeuristic mTextDirectionHeuristic;
 
         /**
          * Constructor.
@@ -208,9 +208,9 @@
          * @param isRtlContext Whether the context is RTL or not.
          */
         private void initialize(boolean isRtlContext) {
-            this.isRtlContext = isRtlContext;
-            textDirectionHeuristic = DEFAULT_TEXT_DIRECTION_HEURISTIC;
-            this.flags = DEFAULT_FLAGS;
+            mIsRtlContext = isRtlContext;
+            mTextDirectionHeuristic = DEFAULT_TEXT_DIRECTION_HEURISTIC;
+            mFlags = DEFAULT_FLAGS;
         }
 
         /**
@@ -219,9 +219,9 @@
          */
         public Builder stereoReset(boolean stereoReset) {
             if (stereoReset) {
-                flags |= FLAG_STEREO_RESET;
+                mFlags |= FLAG_STEREO_RESET;
             } else {
-                flags &= ~FLAG_STEREO_RESET;
+                mFlags &= ~FLAG_STEREO_RESET;
             }
             return this;
         }
@@ -234,7 +234,7 @@
          * @return the builder itself.
          */
         public Builder setTextDirectionHeuristic(TextDirectionHeuristic heuristic) {
-            this.textDirectionHeuristic = heuristic;
+            mTextDirectionHeuristic = heuristic;
             return this;
         }
 
@@ -246,11 +246,11 @@
          * @return A BidiFormatter with the specified options.
          */
         public BidiFormatter build() {
-            if (flags == DEFAULT_FLAGS &&
-                    textDirectionHeuristic == DEFAULT_TEXT_DIRECTION_HEURISTIC) {
-                return getDefaultInstanceFromContext(isRtlContext);
+            if (mFlags == DEFAULT_FLAGS &&
+                    mTextDirectionHeuristic == DEFAULT_TEXT_DIRECTION_HEURISTIC) {
+                return getDefaultInstanceFromContext(mIsRtlContext);
             }
-            return new BidiFormatter(isRtlContext, flags, textDirectionHeuristic);
+            return new BidiFormatter(mIsRtlContext, mFlags, mTextDirectionHeuristic);
         }
     }
 
@@ -268,9 +268,9 @@
             DEFAULT_FLAGS,
             DEFAULT_TEXT_DIRECTION_HEURISTIC);
 
-    private final boolean isRtlContext;
-    private final int flags;
-    private final TextDirectionHeuristic defaultTextDirectionHeuristic;
+    private final boolean mIsRtlContext;
+    private final int mFlags;
+    private final TextDirectionHeuristic mDefaultTextDirectionHeuristic;
 
     /**
      * Factory for creating an instance of BidiFormatter given the context directionality.
@@ -296,16 +296,16 @@
      * @param heuristic The default text direction heuristic.
      */
     private BidiFormatter(boolean isRtlContext, int flags, TextDirectionHeuristic heuristic) {
-        this.isRtlContext = isRtlContext;
-        this.flags = flags;
-        this.defaultTextDirectionHeuristic = heuristic;
+        mIsRtlContext = isRtlContext;
+        mFlags = flags;
+        mDefaultTextDirectionHeuristic = heuristic;
     }
 
     /**
      * @return Whether the context directionality is RTL
      */
     public boolean isRtlContext() {
-        return isRtlContext;
+        return mIsRtlContext;
     }
 
     /**
@@ -313,7 +313,7 @@
      * bidi-wrapped, not just after it.
      */
     public boolean getStereoReset() {
-        return (flags & FLAG_STEREO_RESET) != 0;
+        return (mFlags & FLAG_STEREO_RESET) != 0;
     }
 
     /**
@@ -384,7 +384,7 @@
      *     context; else, the empty string.
      */
     public String dirAttr(boolean isRtl) {
-        return (isRtl != isRtlContext) ? (isRtl ? DIR_RTL_STRING :  DIR_LTR_STRING) : EMPTY_STRING;
+        return (isRtl != mIsRtlContext) ? (isRtl ? DIR_RTL_STRING :  DIR_LTR_STRING) : EMPTY_STRING;
     }
 
     /**
@@ -401,7 +401,7 @@
      *     else, the empty string.
      */
     public String markAfter(String str) {
-        return markAfter(str, defaultTextDirectionHeuristic);
+        return markAfter(str, mDefaultTextDirectionHeuristic);
     }
 
     /**
@@ -417,10 +417,10 @@
     public String markAfter(String str, TextDirectionHeuristic heuristic) {
         final boolean isRtl = heuristic.isRtl(str, 0, str.length());
         // getExitDir() is called only if needed (short-circuit).
-        if (!isRtlContext && (isRtl || getExitDir(str) == DIR_RTL)) {
+        if (!mIsRtlContext && (isRtl || getExitDir(str) == DIR_RTL)) {
             return LRM_STRING;
         }
-        if (isRtlContext && (!isRtl || getExitDir(str) == DIR_LTR)) {
+        if (mIsRtlContext && (!isRtl || getExitDir(str) == DIR_LTR)) {
             return RLM_STRING;
         }
         return EMPTY_STRING;
@@ -440,7 +440,7 @@
      *     else, the empty string.
      */
     public String markBefore(String str) {
-        return markBefore(str, defaultTextDirectionHeuristic);
+        return markBefore(str, mDefaultTextDirectionHeuristic);
     }
 
     /**
@@ -456,10 +456,10 @@
     public String markBefore(String str, TextDirectionHeuristic heuristic) {
         final boolean isRtl = heuristic.isRtl(str, 0, str.length());
         // getEntryDir() is called only if needed (short-circuit).
-        if (!isRtlContext && (isRtl || getEntryDir(str) == DIR_RTL)) {
+        if (!mIsRtlContext && (isRtl || getEntryDir(str) == DIR_RTL)) {
             return LRM_STRING;
         }
-        if (isRtlContext && (!isRtl || getEntryDir(str) == DIR_LTR)) {
+        if (mIsRtlContext && (!isRtl || getEntryDir(str) == DIR_LTR)) {
             return RLM_STRING;
         }
         return EMPTY_STRING;
@@ -470,7 +470,7 @@
      * directionality, RLM for RTL context directionality).
      */
     public String mark() {
-        return isRtlContext ? RLM_STRING : LRM_STRING;
+        return mIsRtlContext ? RLM_STRING : LRM_STRING;
     }
 
     /**
@@ -478,7 +478,7 @@
      * returns "left".
      */
     public String startEdge() {
-        return isRtlContext  ? RIGHT : LEFT;
+        return mIsRtlContext ? RIGHT : LEFT;
     }
 
     /**
@@ -486,7 +486,7 @@
      * returns "right".
      */
     public String endEdge() {
-        return isRtlContext ? LEFT : RIGHT;
+        return mIsRtlContext ? LEFT : RIGHT;
     }
 
     /**
@@ -497,7 +497,7 @@
      *          false.
      */
     public boolean isRtl(String str) {
-        return defaultTextDirectionHeuristic.isRtl(str, 0, str.length());
+        return mDefaultTextDirectionHeuristic.isRtl(str, 0, str.length());
     }
 
     /**
@@ -536,7 +536,7 @@
             result.append(markBefore(origStr,
                     isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
         }
-        if (isRtl != isRtlContext) {
+        if (isRtl != mIsRtlContext) {
             result.append("<span ").append(dirAttr(isRtl)).append('>').append(str).append("</span>");
         } else {
             result.append(str);
@@ -570,7 +570,7 @@
      * @return Input string after applying the above processing.
      */
     public String spanWrap(String str, boolean isolate) {
-        return spanWrap(str, defaultTextDirectionHeuristic, isolate);
+        return spanWrap(str, mDefaultTextDirectionHeuristic, isolate);
     }
 
     /**
@@ -581,7 +581,7 @@
      * @return Input string after applying the above processing.
      */
     public String spanWrap(String str) {
-        return spanWrap(str, defaultTextDirectionHeuristic, true /* isolate */);
+        return spanWrap(str, mDefaultTextDirectionHeuristic, true /* isolate */);
     }
 
     /**
@@ -620,7 +620,7 @@
             result.append(markBefore(str,
                     isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
         }
-        if (isRtl != isRtlContext) {
+        if (isRtl != mIsRtlContext) {
             result.append(isRtl ? RLE : LRE);
             result.append(str);
             result.append(PDF);
@@ -656,7 +656,7 @@
      * @return Input string after applying the above processing.
      */
     public String unicodeWrap(String str, boolean isolate) {
-        return unicodeWrap(str, defaultTextDirectionHeuristic, isolate);
+        return unicodeWrap(str, mDefaultTextDirectionHeuristic, isolate);
     }
 
     /**
@@ -667,7 +667,7 @@
      * @return Input string after applying the above processing.
      */
     public String unicodeWrap(String str) {
-        return unicodeWrap(str, defaultTextDirectionHeuristic, true /* isolate */);
+        return unicodeWrap(str, mDefaultTextDirectionHeuristic, true /* isolate */);
     }
 
     /**
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 7e230ac..c497e35 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -31,181 +31,89 @@
 import java.util.TimeZone;
 import java.text.SimpleDateFormat;
 
+import libcore.icu.ICU;
 import libcore.icu.LocaleData;
 
 /**
-    Utility class for producing strings with formatted date/time.
-
-    <p>
-    Most callers should avoid supplying their own format strings to this
-    class' {@code format} methods and rely on the correctly localized ones
-    supplied by the system. This class' factory methods return
-    appropriately-localized {@link java.text.DateFormat} instances, suitable
-    for both formatting and parsing dates. For the canonical documentation
-    of format strings, see {@link java.text.SimpleDateFormat}.
-    </p>
-    <p>
-    The format methods in this class takes as inputs a format string and a representation of a date/time.
-    The format string controls how the output is generated.
-    This class only supports a subset of the full Unicode specification.
-    Use {@link java.text.SimpleDateFormat} if you need more.
-    Formatting characters may be repeated in order to get more detailed representations
-    of that field.  For instance, the format character &apos;M&apos; is used to
-    represent the month.  Depending on how many times that character is repeated
-    you get a different representation.
-    </p>
-    <p>
-    For the month of September:<br/>
-    M -&gt; 9<br/>
-    MM -&gt; 09<br/>
-    MMM -&gt; Sep<br/>
-    MMMM -&gt; September
-    </p>
-    <p>
-    The effects of the duplication vary depending on the nature of the field.
-    See the notes on the individual field formatters for details.  For purely numeric
-    fields such as <code>HOUR</code> adding more copies of the designator will
-    zero-pad the value to that number of characters.
-    </p>
-    <p>
-    For 7 minutes past the hour:<br/>
-    m -&gt; 7<br/>
-    mm -&gt; 07<br/>
-    mmm -&gt; 007<br/>
-    mmmm -&gt; 0007
-    </p>
-    <p>
-    Examples for April 6, 1970 at 3:23am:<br/>
-    &quot;MM/dd/yy h:mmaa&quot; -&gt; &quot;04/06/70 3:23am&quot<br/>
-    &quot;MMM dd, yyyy h:mmaa&quot; -&gt; &quot;Apr 6, 1970 3:23am&quot<br/>
-    &quot;MMMM dd, yyyy h:mmaa&quot; -&gt; &quot;April 6, 1970 3:23am&quot<br/>
-    &quot;E, MMMM dd, yyyy h:mmaa&quot; -&gt; &quot;Mon, April 6, 1970 3:23am&<br/>
-    &quot;EEEE, MMMM dd, yyyy h:mmaa&quot; -&gt; &quot;Monday, April 6, 1970 3:23am&quot;<br/>
-    &quot;&apos;Noteworthy day: &apos;M/d/yy&quot; -&gt; &quot;Noteworthy day: 4/6/70&quot;
+ * Utility class for producing strings with formatted date/time.
+ *
+ * <p>Most callers should avoid supplying their own format strings to this
+ * class' {@code format} methods and rely on the correctly localized ones
+ * supplied by the system. This class' factory methods return
+ * appropriately-localized {@link java.text.DateFormat} instances, suitable
+ * for both formatting and parsing dates. For the canonical documentation
+ * of format strings, see {@link java.text.SimpleDateFormat}.
+ *
+ * <p>In cases where the system does not provide a suitable pattern,
+ * this class offers the {@link #getBestDateTimePattern} method.
+ *
+ * <p>The {@code format} methods in this class implement a subset of Unicode
+ * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> patterns.
+ * The subset currently supported by this class includes the following format characters:
+ * {@code acdEHhLKkLMmsyz}. Up to API level 17, only {@code adEhkMmszy} were supported.
+ * Note that this class incorrectly implements {@code k} as if it were {@code H} for backwards
+ * compatibility.
+ *
+ * <p>See {@link java.text.SimpleDateFormat} for more documentation
+ * about patterns, or if you need a more complete or correct implementation.
+ * Note that the non-{@code format} methods in this class are implemented by
+ * {@code SimpleDateFormat}.
  */
-
 public class DateFormat {
-    /**
-        Text in the format string that should be copied verbatim rather that
-        interpreted as formatting codes must be surrounded by the <code>QUOTE</code>
-        character.  If you need to embed a literal <code>QUOTE</code> character in
-        the output text then use two in a row.
-     */
+    /** @deprecated Use a literal {@code '} instead. */
+    @Deprecated
     public  static final char    QUOTE                  =    '\'';
-    
-    /**
-        This designator indicates whether the <code>HOUR</code> field is before
-        or after noon.  The output is lower-case.
-     
-        Examples:
-        a -> a or p
-        aa -> am or pm
-     */
+
+    /** @deprecated Use a literal {@code 'a'} instead. */
+    @Deprecated
     public  static final char    AM_PM                  =    'a';
 
-    /**
-        This designator indicates whether the <code>HOUR</code> field is before
-        or after noon.  The output is capitalized.
-     
-        Examples:
-        A -> A or P
-        AA -> AM or PM
-     */
+    /** @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'. */
+    @Deprecated
     public  static final char    CAPITAL_AM_PM          =    'A';
 
-    /**
-        This designator indicates the day of the month.
-         
-        Examples for the 9th of the month:
-        d -> 9
-        dd -> 09
-     */
+    /** @deprecated Use a literal {@code 'd'} instead. */
+    @Deprecated
     public  static final char    DATE                   =    'd';
 
-    /**
-        This designator indicates the name of the day of the week.
-     
-        Examples for Sunday:
-        E -> Sun
-        EEEE -> Sunday
-     */
+    /** @deprecated Use a literal {@code 'E'} instead. */
+    @Deprecated
     public  static final char    DAY                    =    'E';
 
-    /**
-        This designator indicates the hour of the day in 12 hour format.
-     
-        Examples for 3pm:
-        h -> 3
-        hh -> 03
-     */
+    /** @deprecated Use a literal {@code 'h'} instead. */
+    @Deprecated
     public  static final char    HOUR                   =    'h';
 
     /**
-        This designator indicates the hour of the day in 24 hour format.
-     
-        Example for 3pm:
-        k -> 15
-
-        Examples for midnight:
-        k -> 0
-        kk -> 00
+     * @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat}
+     * and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including
+     * Jelly Bean MR-1) instead. Note that the two are incompatible.
      */
+    @Deprecated
     public  static final char    HOUR_OF_DAY            =    'k';
 
-    /**
-        This designator indicates the minute of the hour.
-     
-        Examples for 7 minutes past the hour:
-        m -> 7
-        mm -> 07
-     */
+    /** @deprecated Use a literal {@code 'm'} instead. */
+    @Deprecated
     public  static final char    MINUTE                 =    'm';
 
-    /**
-        This designator indicates the month of the year. See also
-        {@link #STANDALONE_MONTH}.
-     
-        Examples for September:
-        M -> 9
-        MM -> 09
-        MMM -> Sep
-        MMMM -> September
-     */
+    /** @deprecated Use a literal {@code 'M'} instead. */
+    @Deprecated
     public  static final char    MONTH                  =    'M';
 
-    /**
-        This designator indicates the standalone month of the year,
-        necessary in some format strings in some languages. For
-        example, Russian distinguishes between the "June" in
-        "June" and that in "June 2010".
-     */
+    /** @deprecated Use a literal {@code 'L'} instead. */
+    @Deprecated
     public  static final char    STANDALONE_MONTH       =    'L';
 
-    /**
-        This designator indicates the seconds of the minute.
-     
-        Examples for 7 seconds past the minute:
-        s -> 7
-        ss -> 07
-     */
+    /** @deprecated Use a literal {@code 's'} instead. */
+    @Deprecated
     public  static final char    SECONDS                =    's';
 
-    /**
-        This designator indicates the offset of the timezone from GMT.
-     
-        Example for US/Pacific timezone:
-        z -> -0800
-        zz -> PST
-     */
+    /** @deprecated Use a literal {@code 'z'} instead. */
+    @Deprecated
     public  static final char    TIME_ZONE              =    'z';
 
-    /**
-        This designator indicates the year.
-     
-        Examples for 2006
-        y -> 06
-        yyyy -> 2006
-     */
+    /** @deprecated Use a literal {@code 'y'} instead. */
+    @Deprecated
     public  static final char    YEAR                   =    'y';
 
 
@@ -233,8 +141,7 @@
             }
 
             java.text.DateFormat natural =
-                java.text.DateFormat.getTimeInstance(
-                    java.text.DateFormat.LONG, locale);
+                java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale);
 
             if (natural instanceof SimpleDateFormat) {
                 SimpleDateFormat sdf = (SimpleDateFormat) natural;
@@ -261,19 +168,59 @@
     }
 
     /**
+     * Returns the best possible localized form of the given skeleton for the given
+     * locale. A skeleton is similar to, and uses the same format characters as, a Unicode
+     * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a>
+     * pattern.
+     *
+     * <p>One difference is that order is irrelevant. For example, "MMMMd" will return
+     * "MMMM d" in the {@code en_US} locale, but "d. MMMM" in the {@code de_CH} locale.
+     *
+     * <p>Note also in that second example that the necessary punctuation for German was
+     * added. For the same input in {@code es_ES}, we'd have even more extra text:
+     * "d 'de' MMMM".
+     *
+     * <p>This method will automatically correct for grammatical necessity. Given the
+     * same "MMMMd" input, this method will return "d LLLL" in the {@code fa_IR} locale,
+     * where stand-alone months are necessary. Lengths are preserved where meaningful,
+     * so "Md" would give a different result to "MMMd", say, except in a locale such as
+     * {@code ja_JP} where there is only one length of month.
+     *
+     * <p>This method will only return patterns that are in CLDR, and is useful whenever
+     * you know what elements you want in your format string but don't want to make your
+     * code specific to any one locale.
+     *
+     * @param locale the locale into which the skeleton should be localized
+     * @param skeleton a skeleton as described above
+     * @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
+     */
+    public static String getBestDateTimePattern(Locale locale, String skeleton) {
+        return ICU.getBestDateTimePattern(skeleton, locale.toString());
+    }
+
+    /**
      * Returns a {@link java.text.DateFormat} object that can format the time according
      * to the current locale and the user's 12-/24-hour clock preference.
      * @param context the application context
      * @return the {@link java.text.DateFormat} object that properly formats the time.
      */
     public static java.text.DateFormat getTimeFormat(Context context) {
-        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
-        boolean is24 = is24HourFormat(context);
-        return new java.text.SimpleDateFormat(is24 ? d.timeFormat24 : d.timeFormat12);
+        return new java.text.SimpleDateFormat(getTimeFormatString(context));
     }
 
     /**
-     * Returns a {@link java.text.DateFormat} object that can format the date 
+     * Returns a String pattern that can be used to format the time according
+     * to the current locale and the user's 12-/24-hour clock preference.
+     * @param context the application context
+     * @hide
+     */
+    public static String getTimeFormatString(Context context) {
+        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
+        return is24HourFormat(context) ? d.timeFormat24 : d.timeFormat12;
+    }
+
+    /**
+     * Returns a {@link java.text.DateFormat} object that can format the date
      * in short form (such as 12/31/1999) according
      * to the current locale and the user's date-order preference.
      * @param context the application context
@@ -298,7 +245,6 @@
     public static java.text.DateFormat getDateFormatForSetting(Context context,
                                                                String value) {
         String format = getDateFormatStringForSetting(context, value);
-
         return new java.text.SimpleDateFormat(format);
     }
 
@@ -342,10 +288,10 @@
         value = context.getString(R.string.numeric_date_format);
         return value;
     }
-    
+
     /**
      * Returns a {@link java.text.DateFormat} object that can format the date
-     * in long form (such as December 31, 1999) for the current locale.
+     * in long form (such as {@code Monday, January 3, 2000}) for the current locale.
      * @param context the application context
      * @return the {@link java.text.DateFormat} object that formats the date in long form.
      */
@@ -355,7 +301,7 @@
 
     /**
      * Returns a {@link java.text.DateFormat} object that can format the date
-     * in medium form (such as Dec. 31, 1999) for the current locale.
+     * in medium form (such as {@code Jan 3, 2000}) for the current locale.
      * @param context the application context
      * @return the {@link java.text.DateFormat} object that formats the date in long form.
      */
@@ -365,13 +311,13 @@
 
     /**
      * Gets the current date format stored as a char array. The array will contain
-     * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order    
+     * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order
      * specified by the user's format preference.  Note that this order is
      * only appropriate for all-numeric dates; spelled-out (MEDIUM and LONG)
      * dates will generally contain other punctuation, spaces, or words,
      * not just the day, month, and year, and not necessarily in the same
      * order returned here.
-     */    
+     */
     public static char[] getDateFormatOrder(Context context) {
         char[] order = new char[] {DATE, MONTH, YEAR};
         String value = getDateFormatString(context);
@@ -401,7 +347,7 @@
         }
         return order;
     }
-    
+
     private static String getDateFormatString(Context context) {
         String value = Settings.System.getString(context.getContentResolver(),
                 Settings.System.DATE_FORMAT);
@@ -410,7 +356,7 @@
     }
 
     /**
-     * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a 
+     * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a
      * CharSequence containing the requested date.
      * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
      * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT
@@ -428,22 +374,20 @@
      * @return a {@link CharSequence} containing the requested text
      */
     public static CharSequence format(CharSequence inFormat, Date inDate) {
-        Calendar    c = new GregorianCalendar();
-        
+        Calendar c = new GregorianCalendar();
         c.setTime(inDate);
-        
         return format(inFormat, c);
     }
 
     /**
      * Indicates whether the specified format string contains seconds.
-     * 
+     *
      * Always returns false if the input format is null.
-     * 
+     *
      * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
-     *                 
+     *
      * @return true if the format string contains {@link #SECONDS}, false otherwise
-     * 
+     *
      * @hide
      */
     public static boolean hasSeconds(CharSequence inFormat) {
@@ -508,24 +452,23 @@
     }
 
     /**
-     * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence 
+     * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence
      * containing the requested date.
      * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
      * @param inDate the date to format
      * @return a {@link CharSequence} containing the requested text
      */
     public static CharSequence format(CharSequence inFormat, Calendar inDate) {
-        SpannableStringBuilder      s = new SpannableStringBuilder(inFormat);
-        int             c;
-        int             count;
+        SpannableStringBuilder s = new SpannableStringBuilder(inFormat);
+        int count;
+
+        LocaleData localeData = LocaleData.get(Locale.getDefault());
 
         int len = inFormat.length();
 
         for (int i = 0; i < len; i += count) {
-            int temp;
-
             count = 1;
-            c = s.charAt(i);
+            int c = s.charAt(i);
 
             if (c == QUOTE) {
                 count = appendQuotedText(s, i, len);
@@ -538,102 +481,105 @@
             }
 
             String replacement;
-
             switch (c) {
-                case AM_PM:
-                    replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM));
+                case 'A':
+                case 'a':
+                    replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
                     break;
-                                        
-                case CAPITAL_AM_PM:
-                    //FIXME: this is the same as AM_PM? no capital?
-                    replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM));
-                    break;
-                
-                case DATE:
+                case 'd':
                     replacement = zeroPad(inDate.get(Calendar.DATE), count);
                     break;
-                    
-                case DAY:
-                    temp = inDate.get(Calendar.DAY_OF_WEEK);
-                    replacement = DateUtils.getDayOfWeekString(temp,
-                                                               count < 4 ? 
-                                                               DateUtils.LENGTH_MEDIUM : 
-                                                               DateUtils.LENGTH_LONG);
+                case 'c':
+                case 'E':
+                    replacement = getDayOfWeekString(localeData,
+                                                     inDate.get(Calendar.DAY_OF_WEEK), count, c);
                     break;
-                    
-                case HOUR:
-                    temp = inDate.get(Calendar.HOUR);
-
-                    if (0 == temp)
-                        temp = 12;
-                    
-                    replacement = zeroPad(temp, count);
+                case 'K': // hour in am/pm (0-11)
+                case 'h': // hour in am/pm (1-12)
+                    {
+                        int hour = inDate.get(Calendar.HOUR);
+                        if (c == 'h' && hour == 0) {
+                            hour = 12;
+                        }
+                        replacement = zeroPad(hour, count);
+                    }
                     break;
-                    
-                case HOUR_OF_DAY:
-                    replacement = zeroPad(inDate.get(Calendar.HOUR_OF_DAY), count);
+                case 'H': // hour in day (0-23)
+                case 'k': // hour in day (1-24) [but see note below]
+                    {
+                        int hour = inDate.get(Calendar.HOUR_OF_DAY);
+                        // Historically on Android 'k' was interpreted as 'H', which wasn't
+                        // implemented, so pretty much all callers that want to format 24-hour
+                        // times are abusing 'k'. http://b/8359981.
+                        if (false && c == 'k' && hour == 0) {
+                            hour = 24;
+                        }
+                        replacement = zeroPad(hour, count);
+                    }
                     break;
-                    
-                case MINUTE:
+                case 'L':
+                case 'M':
+                    replacement = getMonthString(localeData,
+                                                 inDate.get(Calendar.MONTH), count, c);
+                    break;
+                case 'm':
                     replacement = zeroPad(inDate.get(Calendar.MINUTE), count);
                     break;
-                    
-                case MONTH:
-                case STANDALONE_MONTH:
-                    replacement = getMonthString(inDate, count, c);
-                    break;
-
-                case SECONDS:
+                case 's':
                     replacement = zeroPad(inDate.get(Calendar.SECOND), count);
                     break;
-                    
-                case TIME_ZONE:
+                case 'y':
+                    replacement = getYearString(inDate.get(Calendar.YEAR), count);
+                    break;
+                case 'z':
                     replacement = getTimeZoneString(inDate, count);
                     break;
-                    
-                case YEAR:
-                    replacement = getYearString(inDate, count);
-                    break;
-
                 default:
                     replacement = null;
                     break;
             }
-            
+
             if (replacement != null) {
                 s.replace(i, i + count, replacement);
                 count = replacement.length(); // CARE: count is used in the for loop above
                 len = s.length();
             }
         }
-        
-        if (inFormat instanceof Spanned)
+
+        if (inFormat instanceof Spanned) {
             return new SpannedString(s);
-        else
+        } else {
             return s.toString();
+        }
     }
-    
-    private static String getMonthString(Calendar inDate, int count, int kind) {
-        boolean standalone = (kind == STANDALONE_MONTH);
-        int month = inDate.get(Calendar.MONTH);
-        
-        if (count >= 4) {
-            return standalone
-                ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_LONG)
-                : DateUtils.getMonthString(month, DateUtils.LENGTH_LONG);
+
+    private static String getDayOfWeekString(LocaleData ld, int day, int count, int kind) {
+        boolean standalone = (kind == 'c');
+        if (count == 5) {
+            return standalone ? ld.tinyStandAloneWeekdayNames[day] : ld.tinyWeekdayNames[day];
+        } else if (count == 4) {
+            return standalone ? ld.longStandAloneWeekdayNames[day] : ld.longWeekdayNames[day];
+        } else {
+            return standalone ? ld.shortStandAloneWeekdayNames[day] : ld.shortWeekdayNames[day];
+        }
+    }
+
+    private static String getMonthString(LocaleData ld, int month, int count, int kind) {
+        boolean standalone = (kind == 'L');
+        if (count == 5) {
+            return standalone ? ld.tinyStandAloneMonthNames[month] : ld.tinyMonthNames[month];
+        } else if (count == 4) {
+            return standalone ? ld.longStandAloneMonthNames[month] : ld.longMonthNames[month];
         } else if (count == 3) {
-            return standalone
-                ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_MEDIUM)
-                : DateUtils.getMonthString(month, DateUtils.LENGTH_MEDIUM);
+            return standalone ? ld.shortStandAloneMonthNames[month] : ld.shortMonthNames[month];
         } else {
             // Calendar.JANUARY == 0, so add 1 to month.
             return zeroPad(month+1, count);
         }
     }
-        
+
     private static String getTimeZoneString(Calendar inDate, int count) {
         TimeZone tz = inDate.getTimeZone();
-        
         if (count < 2) { // FIXME: shouldn't this be <= 2 ?
             return formatZoneOffset(inDate.get(Calendar.DST_OFFSET) +
                                     inDate.get(Calendar.ZONE_OFFSET),
@@ -662,13 +608,12 @@
         tb.append(zeroPad(minutes, 2));
         return tb.toString();
     }
-    
-    private static String getYearString(Calendar inDate, int count) {
-        int year = inDate.get(Calendar.YEAR);
+
+    private static String getYearString(int year, int count) {
         return (count <= 2) ? zeroPad(year % 100, 2)
                             : String.format(Locale.getDefault(), "%d", year);
     }
-   
+
     private static int appendQuotedText(SpannableStringBuilder s, int i, int len) {
         if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
             s.delete(i, i + 1);
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index 8920b24..5a88cf6 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -39,7 +39,6 @@
 {
     private static final Object sLock = new Object();
     private static Configuration sLastConfig;
-    private static java.text.DateFormat sStatusTimeFormat;
     private static String sElapsedFormatMMSS;
     private static String sElapsedFormatHMMSS;
 
@@ -95,14 +94,14 @@
     // translated.
     /**
      * This is not actually the preferred 24-hour date format in all locales.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final String HOUR_MINUTE_24 = "%H:%M";
     public static final String MONTH_FORMAT = "%B";
     /**
      * This is not actually a useful month name in all locales.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final String ABBREV_MONTH_FORMAT = "%b";
@@ -118,7 +117,7 @@
     // The index is constructed from a bit-wise OR of the boolean values:
     // {showTime, showYear, showWeekDay}.  For example, if showYear and
     // showWeekDay are both true, then the index would be 3.
-    /** @deprecated do not use. */
+    /** @deprecated Do not use. */
     public static final int sameYearTable[] = {
         com.android.internal.R.string.same_year_md1_md2,
         com.android.internal.R.string.same_year_wday1_md1_wday2_md2,
@@ -145,7 +144,7 @@
     // The index is constructed from a bit-wise OR of the boolean values:
     // {showTime, showYear, showWeekDay}.  For example, if showYear and
     // showWeekDay are both true, then the index would be 3.
-    /** @deprecated do not use. */
+    /** @deprecated Do not use. */
     public static final int sameMonthTable[] = {
         com.android.internal.R.string.same_month_md1_md2,
         com.android.internal.R.string.same_month_wday1_md1_wday2_md2,
@@ -172,7 +171,7 @@
      *
      * @more <p>
      *       e.g. "Sunday" or "January"
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final int LENGTH_LONG = 10;
@@ -183,7 +182,7 @@
      *
      * @more <p>
      *       e.g. "Sun" or "Jan"
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final int LENGTH_MEDIUM = 20;
@@ -195,7 +194,7 @@
      * <p>e.g. "Su" or "Jan"
      * <p>In most languages, the results returned for LENGTH_SHORT will be the same as
      * the results returned for {@link #LENGTH_MEDIUM}.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final int LENGTH_SHORT = 30;
@@ -204,7 +203,7 @@
      * Request an even shorter abbreviated version of the name.
      * Do not use this.  Currently this will always return the same result
      * as {@link #LENGTH_SHORT}.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final int LENGTH_SHORTER = 40;
@@ -216,7 +215,7 @@
      * <p>e.g. "S", "T", "T" or "J"
      * <p>In some languages, the results returned for LENGTH_SHORTEST will be the same as
      * the results returned for {@link #LENGTH_SHORT}.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static final int LENGTH_SHORTEST = 50;
@@ -232,7 +231,7 @@
      *               Undefined lengths will return {@link #LENGTH_MEDIUM}
      *               but may return something different in the future.
      * @throws IndexOutOfBoundsException if the dayOfWeek is out of bounds.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static String getDayOfWeekString(int dayOfWeek, int abbrev) {
@@ -254,7 +253,7 @@
      * @param ampm Either {@link Calendar#AM Calendar.AM} or {@link Calendar#PM Calendar.PM}.
      * @throws IndexOutOfBoundsException if the ampm is out of bounds.
      * @return Localized version of "AM" or "PM".
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static String getAMPMString(int ampm) {
@@ -270,14 +269,10 @@
      *               Undefined lengths will return {@link #LENGTH_MEDIUM}
      *               but may return something different in the future.
      * @return Localized month of the year.
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
+     * @deprecated Use {@link java.text.SimpleDateFormat} instead.
      */
     @Deprecated
     public static String getMonthString(int month, int abbrev) {
-        // Note that here we use d.shortMonthNames for MEDIUM, SHORT and SHORTER.
-        // This is a shortcut to not spam the translators with too many variations
-        // of the same string.  If we find that in a language the distinction
-        // is necessary, we can can add more without changing this API.
         LocaleData d = LocaleData.get(Locale.getDefault());
         String[] names;
         switch (abbrev) {
@@ -292,41 +287,6 @@
     }
 
     /**
-     * Return a localized string for the month of the year, for
-     * contexts where the month is not formatted together with
-     * a day of the month.
-     *
-     * @param month One of {@link Calendar#JANUARY Calendar.JANUARY},
-     *               {@link Calendar#FEBRUARY Calendar.FEBRUARY}, etc.
-     * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_MEDIUM},
-     *               or {@link #LENGTH_SHORTEST}.
-     *               Undefined lengths will return {@link #LENGTH_MEDIUM}
-     *               but may return something different in the future.
-     * @return Localized month of the year.
-     * @hide Pending API council approval
-     * @deprecated use {@link java.text.SimpleDateFormat} instead.
-     */
-    @Deprecated
-    public static String getStandaloneMonthString(int month, int abbrev) {
-        // Note that here we use d.shortMonthNames for MEDIUM, SHORT and SHORTER.
-        // This is a shortcut to not spam the translators with too many variations
-        // of the same string.  If we find that in a language the distinction
-        // is necessary, we can can add more without changing this API.
-        LocaleData d = LocaleData.get(Locale.getDefault());
-        String[] names;
-        switch (abbrev) {
-            case LENGTH_LONG:       names = d.longStandAloneMonthNames;
-                                                            break;
-            case LENGTH_MEDIUM:     names = d.shortMonthNames; break;
-            case LENGTH_SHORT:      names = d.shortMonthNames; break;
-            case LENGTH_SHORTER:    names = d.shortMonthNames; break;
-            case LENGTH_SHORTEST:   names = d.tinyMonthNames;  break;
-            default:                names = d.shortMonthNames; break;
-        }
-        return names[month];
-    }
-
-    /**
      * Returns a string describing the elapsed time since startTime.
      * @param startTime some time in the past.
      * @return a String object containing the elapsed time.
@@ -429,20 +389,7 @@
                 }
             }
         } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
-            count = getNumberOfDaysPassed(time, now);
-            if (past) {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_num_days_ago;
-                } else {
-                    resId = com.android.internal.R.plurals.num_days_ago;
-                }
-            } else {
-                if (abbrevRelative) {
-                    resId = com.android.internal.R.plurals.abbrev_in_num_days;
-                } else {
-                    resId = com.android.internal.R.plurals.in_num_days;
-                }
-            }
+            return getRelativeDayString(r, time, now);
         } else {
             // We know that we won't be showing the time, so it is safe to pass
             // in a null context.
@@ -454,24 +401,6 @@
     }
 
     /**
-     * Returns the number of days passed between two dates.
-     *
-     * @param date1 first date
-     * @param date2 second date
-     * @return number of days passed between to dates.
-     */
-    private synchronized static long getNumberOfDaysPassed(long date1, long date2) {
-        if (sThenTime == null) {
-            sThenTime = new Time();
-        }
-        sThenTime.set(date1);
-        int day1 = Time.getJulianDay(date1, sThenTime.gmtoff);
-        sThenTime.set(date2);
-        int day2 = Time.getJulianDay(date2, sThenTime.gmtoff);
-        return Math.abs(day2 - day1);
-    }
-
-    /**
      * Return string describing the elapsed time since startTime formatted like
      * "[relative time/date], [time]".
      * <p>
@@ -529,28 +458,29 @@
      * today this function returns "Today", if the day was a week ago it returns "7 days ago", and
      * if the day is in 2 weeks it returns "in 14 days".
      *
-     * @param r the resources to get the strings from
+     * @param r the resources
      * @param day the relative day to describe in UTC milliseconds
      * @param today the current time in UTC milliseconds
-     * @return a formatting string
      */
     private static final String getRelativeDayString(Resources r, long day, long today) {
+        Locale locale = r.getConfiguration().locale;
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+
+        // TODO: use TimeZone.getOffset instead.
         Time startTime = new Time();
         startTime.set(day);
+        int startDay = Time.getJulianDay(day, startTime.gmtoff);
+
         Time currentTime = new Time();
         currentTime.set(today);
-
-        int startDay = Time.getJulianDay(day, startTime.gmtoff);
         int currentDay = Time.getJulianDay(today, currentTime.gmtoff);
 
         int days = Math.abs(currentDay - startDay);
         boolean past = (today > day);
 
         // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
-        Locale locale = r.getConfiguration().locale;
-        if (locale == null) {
-            locale = Locale.getDefault();
-        }
         if (days == 1) {
             if (past) {
                 return LocaleData.get(locale).yesterday;
@@ -583,25 +513,12 @@
         Configuration cfg = r.getConfiguration();
         if (sLastConfig == null || !sLastConfig.equals(cfg)) {
             sLastConfig = cfg;
-            sStatusTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT);
             sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss);
             sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss);
         }
     }
 
     /**
-     * Format a time so it appears like it would in the status bar clock.
-     * @deprecated use {@link #DateFormat.getTimeFormat(Context)} instead.
-     * @hide
-     */
-    public static final CharSequence timeString(long millis) {
-        synchronized (sLock) {
-            initFormatStringsLocked();
-            return sStatusTimeFormat.format(millis);
-        }
-    }
-
-    /**
      * Return given duration in a human-friendly format. For example, "4
      * minutes" or "1 second". Returns only largest meaningful unit of time,
      * from seconds up to hours.
@@ -715,18 +632,6 @@
     }
 
     /**
-     * @hide
-     * @deprecated use {@link android.text.format.Time}
-     */
-    public static Calendar newCalendar(boolean zulu)
-    {
-        if (zulu)
-            return Calendar.getInstance(TimeZone.getTimeZone("GMT"));
-
-        return Calendar.getInstance();
-    }
-
-    /**
      * @return true if the supplied when is today else false
      */
     public static boolean isToday(long when) {
@@ -744,127 +649,6 @@
     }
 
     /**
-     * @hide
-     * @deprecated use {@link android.text.format.Time}
-     * Return true if this date string is local time
-     */
-    public static boolean isUTC(String s)
-    {
-        if (s.length() == 16 && s.charAt(15) == 'Z') {
-            return true;
-        }
-        if (s.length() == 9 && s.charAt(8) == 'Z') {
-            // XXX not sure if this case possible/valid
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Return a string containing the date and time in RFC2445 format.
-     * Ensures that the time is written in UTC.  The Calendar class doesn't
-     * really help out with this, so this is slower than it ought to be.
-     *
-     * @param cal the date and time to write
-     * @hide
-     * @deprecated use {@link android.text.format.Time}
-     */
-    public static String writeDateTime(Calendar cal)
-    {
-        TimeZone tz = TimeZone.getTimeZone("GMT");
-        GregorianCalendar c = new GregorianCalendar(tz);
-        c.setTimeInMillis(cal.getTimeInMillis());
-        return writeDateTime(c, true);
-    }
-
-    /**
-     * Return a string containing the date and time in RFC2445 format.
-     *
-     * @param cal the date and time to write
-     * @param zulu If the calendar is in UTC, pass true, and a Z will
-     * be written at the end as per RFC2445.  Otherwise, the time is
-     * considered in localtime.
-     * @hide
-     * @deprecated use {@link android.text.format.Time}
-     */
-    public static String writeDateTime(Calendar cal, boolean zulu)
-    {
-        StringBuilder sb = new StringBuilder();
-        sb.ensureCapacity(16);
-        if (zulu) {
-            sb.setLength(16);
-            sb.setCharAt(15, 'Z');
-        } else {
-            sb.setLength(15);
-        }
-        return writeDateTime(cal, sb);
-    }
-
-    /**
-     * Return a string containing the date and time in RFC2445 format.
-     *
-     * @param cal the date and time to write
-     * @param sb a StringBuilder to use.  It is assumed that setLength
-     *           has already been called on sb to the appropriate length
-     *           which is sb.setLength(zulu ? 16 : 15)
-     * @hide
-     * @deprecated use {@link android.text.format.Time}
-     */
-    public static String writeDateTime(Calendar cal, StringBuilder sb)
-    {
-        int n;
-
-        n = cal.get(Calendar.YEAR);
-        sb.setCharAt(3, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(2, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(1, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(0, (char)('0'+n%10));
-
-        n = cal.get(Calendar.MONTH) + 1;
-        sb.setCharAt(5, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(4, (char)('0'+n%10));
-
-        n = cal.get(Calendar.DAY_OF_MONTH);
-        sb.setCharAt(7, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(6, (char)('0'+n%10));
-
-        sb.setCharAt(8, 'T');
-
-        n = cal.get(Calendar.HOUR_OF_DAY);
-        sb.setCharAt(10, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(9, (char)('0'+n%10));
-
-        n = cal.get(Calendar.MINUTE);
-        sb.setCharAt(12, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(11, (char)('0'+n%10));
-
-        n = cal.get(Calendar.SECOND);
-        sb.setCharAt(14, (char)('0'+n%10));
-        n /= 10;
-        sb.setCharAt(13, (char)('0'+n%10));
-
-        return sb.toString();
-    }
-
-    /**
-     * @hide
-     * @deprecated use {@link android.text.format.Time}
-     */
-    public static void assign(Calendar lval, Calendar rval)
-    {
-        // there should be a faster way.
-        lval.clear();
-        lval.setTimeInMillis(rval.getTimeInMillis());
-    }
-
-    /**
      * Formats a date or a time range according to the local conventions.
      * <p>
      * Note that this is a convenience method. Using it involves creating an
@@ -1096,30 +880,34 @@
         // computation below that'd otherwise be thrown out.
         boolean isInstant = (startMillis == endMillis);
 
-        Time startDate;
+        Calendar startCalendar, endCalendar;
+        Time startDate = new Time();
         if (timeZone != null) {
-            startDate = new Time(timeZone);
+            startCalendar = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
         } else if (useUTC) {
-            startDate = new Time(Time.TIMEZONE_UTC);
+            startCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
         } else {
-            startDate = new Time();
+            startCalendar = Calendar.getInstance();
         }
-        startDate.set(startMillis);
+        startCalendar.setTimeInMillis(startMillis);
+        setTimeFromCalendar(startDate, startCalendar);
 
-        Time endDate;
+        Time endDate = new Time();
         int dayDistance;
         if (isInstant) {
             endDate = startDate;
             dayDistance = 0;
         } else {
             if (timeZone != null) {
-                endDate = new Time(timeZone);
+                endCalendar = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
             } else if (useUTC) {
-                endDate = new Time(Time.TIMEZONE_UTC);
+                endCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
             } else {
-                endDate = new Time();
+                endCalendar = Calendar.getInstance();
             }
-            endDate.set(endMillis);
+            endCalendar.setTimeInMillis(endMillis);
+            setTimeFromCalendar(endDate, endCalendar);
+
             int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff);
             int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff);
             dayDistance = endJulianDay - startJulianDay;
@@ -1462,6 +1250,20 @@
         return formatter.format(fullFormat, timeString, startWeekDayString, dateString);
     }
 
+    private static void setTimeFromCalendar(Time t, Calendar c) {
+        t.hour = c.get(Calendar.HOUR_OF_DAY);
+        t.minute = c.get(Calendar.MINUTE);
+        t.month = c.get(Calendar.MONTH);
+        t.monthDay = c.get(Calendar.DAY_OF_MONTH);
+        t.second = c.get(Calendar.SECOND);
+        t.weekDay = c.get(Calendar.DAY_OF_WEEK) - 1;
+        t.year = c.get(Calendar.YEAR);
+        t.yearDay = c.get(Calendar.DAY_OF_YEAR);
+        t.isDst = (c.get(Calendar.DST_OFFSET) != 0) ? 1 : 0;
+        t.gmtoff = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET);
+        t.timezone = c.getTimeZone().getID();
+    }
+
     /**
      * Formats a date or a time according to the local conventions. There are
      * lots of options that allow the caller to control, for example, if the
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 121c6f2..9c98b98 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -95,16 +95,12 @@
     }
 
     /**
-     * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing
-     * the IP address.  The IP address is expected to be in little-endian format (LSB first). That
-     * is, 0x01020304 will return "4.3.2.1".
+     * Returns a string in the canonical IPv4 format ###.###.###.### from a packed integer
+     * containing the IP address. The IPv4 address is expected to be in little-endian
+     * format (LSB first). That is, 0x01020304 will return "4.3.2.1".
      *
-     * @param ipv4Address the IP address as a packed integer with LSB first.
-     * @return string with canonical IP address format.
-     *
-     * @deprecated this method doesn't support IPv6 addresses. Prefer {@link
-     *     java.net.InetAddress#getHostAddress()}, which supports both IPv4 and
-     *     IPv6 addresses.
+     * @deprecated Use {@link java.net.InetAddress#getHostAddress()}, which supports both IPv4 and
+     *     IPv6 addresses. This method does not support IPv6 addresses.
      */
     @Deprecated
     public static String formatIpAddress(int ipv4Address) {
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 9860588..2bc1c6a 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -16,6 +16,7 @@
 
 package android.text.util;
 
+import android.telephony.PhoneNumberUtils;
 import android.text.method.LinkMovementMethod;
 import android.text.method.MovementMethod;
 import android.text.style.URLSpan;
@@ -32,9 +33,14 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import com.android.i18n.phonenumbers.PhoneNumberMatch;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
+
 /**
  *  Linkify take a piece of text and a regular expression and turns all of the
  *  regex matches in the text into clickable links.  This is particularly
@@ -221,9 +227,7 @@
         }
 
         if ((mask & PHONE_NUMBERS) != 0) {
-            gatherLinks(links, text, Patterns.PHONE,
-                new String[] { "tel:" },
-                sPhoneNumberMatchFilter, sPhoneNumberTransformFilter);
+            gatherTelLinks(links, text);
         }
 
         if ((mask & MAP_ADDRESSES) != 0) {
@@ -443,6 +447,19 @@
         }
     }
 
+    private static final void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s) {
+        PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
+        Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
+                Locale.getDefault().getCountry(), Leniency.POSSIBLE, Long.MAX_VALUE);
+        for (PhoneNumberMatch match : matches) {
+            LinkSpec spec = new LinkSpec();
+            spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
+            spec.start = match.start();
+            spec.end = match.end();
+            links.add(spec);
+        }
+    }
+
     private static final void gatherMapLinks(ArrayList<LinkSpec> links, Spannable s) {
         String string = s.toString();
         String address;
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 470526c..74942ba 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -151,7 +151,7 @@
      * Return the value of 'attribute' as a resource identifier.
      * 
      * <p>Note that this is different than {@link #getAttributeNameResource}
-     * in that it returns a the value contained in this attribute as a
+     * in that it returns the value contained in this attribute as a
      * resource identifier (i.e., a value originally of the form
      * "@package:type/resource"); the other method returns a resource
      * identifier that identifies the name of the attribute.
@@ -230,7 +230,7 @@
      * Return the value of attribute at 'index' as a resource identifier.
      * 
      * <p>Note that this is different than {@link #getAttributeNameResource}
-     * in that it returns a the value contained in this attribute as a
+     * in that it returns the value contained in this attribute as a
      * resource identifier (i.e., a value originally of the form
      * "@package:type/resource"); the other method returns a resource
      * identifier that identifies the name of the attribute.
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 6c48e43..2ec9a7d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -399,12 +399,13 @@
     ///////////////////////////////////////////////////////////////////////////
     
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
+        layer.setLayerPaint(paint);
+
         final GLES20Layer glLayer = (GLES20Layer) layer;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
+        nDrawLayer(mRenderer, glLayer.getLayer(), x, y);
     }
 
-    private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
+    private static native void nDrawLayer(int renderer, int layer, float x, float y);
 
     void interrupt() {
         nInterrupt(mRenderer);
@@ -1162,14 +1163,14 @@
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, index, count, x, y, paint.mNativePaint);
+            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
     
     private static native void nDrawText(int renderer, char[] text, int index, int count,
-            float x, float y, int paint);
+            float x, float y, int bidiFlags, int paint);
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
@@ -1177,14 +1178,16 @@
         try {
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
-                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mNativePaint);
+                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
+                        paint.mNativePaint);
             } else if (text instanceof GraphicsOperations) {
                 ((GraphicsOperations) text).drawText(this, start, end, x, y,
                                                          paint);
             } else {
                 char[] buf = TemporaryBuffer.obtain(end - start);
                 TextUtils.getChars(text, start, end, buf, 0);
-                nDrawText(mRenderer, buf, 0, end - start, x, y, paint.mNativePaint);
+                nDrawText(mRenderer, buf, 0, end - start, x, y,
+                        paint.mBidiFlags, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -1200,20 +1203,21 @@
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, start, end, x, y, paint.mNativePaint);
+            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawText(int renderer, String text, int start, int end,
-            float x, float y, int paint);
+            float x, float y, int bidiFlags, int paint);
 
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
         int modifiers = setupModifiers(paint);
         try {
-            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mNativePaint);
+            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
+                    paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
@@ -1229,14 +1233,14 @@
         int modifiers = setupModifiers(paint);
         try {
             nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
-                    paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawTextOnPath(int renderer, char[] text, int index, int count,
-            int path, float hOffset, float vOffset, int nativePaint);
+            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
 
     @Override
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
@@ -1245,25 +1249,28 @@
         int modifiers = setupModifiers(paint);
         try {
             nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
-                    paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
     }
 
     private static native void nDrawTextOnPath(int renderer, String text, int start, int end,
-            int path, float hOffset, float vOffset, int nativePaint);
+            int path, float hOffset, float vOffset, int bidiFlags, int nativePaint);
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
+            throw new IllegalArgumentException("Unknown direction: " + dir);
+        }
 
         int modifiers = setupModifiers(paint);
         try {
-            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y,
+            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
                     paint.mNativePaint);
         } finally {
             if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
@@ -1271,31 +1278,32 @@
     }
 
     private static native void nDrawTextRun(int renderer, char[] text, int index, int count,
-            int contextIndex, int contextCount, float x, float y, int nativePaint);
+            int contextIndex, int contextCount, float x, float y, int dir, int nativePaint);
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
         if ((start | end | end - start | text.length() - end) < 0) {
             throw new IndexOutOfBoundsException();
         }
 
         int modifiers = setupModifiers(paint);
         try {
+            int flags = dir == 0 ? 0 : 1;
             if (text instanceof String || text instanceof SpannedString ||
                     text instanceof SpannableString) {
                 nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
-                        contextEnd, x, y, paint.mNativePaint);
+                        contextEnd, x, y, flags, paint.mNativePaint);
             } else if (text instanceof GraphicsOperations) {
                 ((GraphicsOperations) text).drawTextRun(this, start, end,
-                        contextStart, contextEnd, x, y, paint);
+                        contextStart, contextEnd, x, y, flags, paint);
             } else {
                 int contextLen = contextEnd - contextStart;
                 int len = end - start;
                 char[] buf = TemporaryBuffer.obtain(contextLen);
                 TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
                 nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
-                        x, y, paint.mNativePaint);
+                        x, y, flags, paint.mNativePaint);
                 TemporaryBuffer.recycle(buf);
             }
         } finally {
@@ -1304,7 +1312,7 @@
     }
 
     private static native void nDrawTextRun(int renderer, String text, int start, int end,
-            int contextStart, int contextEnd, float x, float y, int nativePaint);
+            int contextStart, int contextEnd, float x, float y, int flags, int nativePaint);
 
     @Override
     public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 947cf44..7da2451 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -267,15 +267,15 @@
 
     @Override
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, Paint paint) {
-        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, paint);
+            float x, float y, int dir, Paint paint) {
+        super.drawTextRun(text, index, count, contextIndex, contextCount, x, y, dir, paint);
         recordShaderBitmap(paint);
     }
 
     @Override
     public void drawTextRun(CharSequence text, int start, int end, int contextStart,
-            int contextEnd, float x, float y, Paint paint) {
-        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, paint);
+            int contextEnd, float x, float y, int dir, Paint paint) {
+        super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, dir, paint);
         recordShaderBitmap(paint);
     }
 
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index e086f5a..8308459 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -428,6 +428,8 @@
     interface HardwareDrawCallbacks {
         /**
          * Invoked before a view is drawn by a hardware renderer.
+         * This method can be used to apply transformations to the
+         * canvas but no drawing command should be issued.
          * 
          * @param canvas The Canvas used to render the view.
          */
@@ -435,6 +437,7 @@
 
         /**
          * Invoked after a view is drawn by a hardware renderer.
+         * It is safe to invoke drawing commands from this method.
          * 
          * @param canvas The Canvas used to render the view.
          */
@@ -448,10 +451,8 @@
      * @param attachInfo AttachInfo tied to the specified view.
      * @param callbacks Callbacks invoked when drawing happens.
      * @param dirty The dirty rectangle to update, can be null.
-     * 
-     * @return true if the dirty rect was ignored, false otherwise
      */
-    abstract boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
+    abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
             Rect dirty);
 
     /**
@@ -989,11 +990,7 @@
                             mCanvas = createCanvas();
                             mCanvas.setName(mName);
                         }
-                        if (mCanvas != null) {
-                            setEnabled(true);
-                        } else {
-                            Log.w(LOG_TAG, "Hardware accelerated Canvas could not be created");
-                        }
+                        setEnabled(true);
                     }
 
                     return mCanvas != null;
@@ -1337,7 +1334,7 @@
         }
 
         @Override
-        boolean draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
+        void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
                 Rect dirty) {
             if (canDraw()) {
                 if (!hasDirtyRegions()) {
@@ -1371,7 +1368,7 @@
                         callbacks.onHardwarePreDraw(canvas);
 
                         if (displayList != null) {
-                            status = drawDisplayList(attachInfo, canvas, displayList, status);
+                            status |= drawDisplayList(attachInfo, canvas, displayList, status);
                         } else {
                             // Shouldn't reach here
                             view.draw(canvas);
@@ -1398,11 +1395,8 @@
                     }
 
                     attachInfo.mIgnoreDirtyState = false;
-                    return dirty == null;
                 }
             }
-
-            return false;
         }
 
         private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f0c6241..8ed4a86 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -60,8 +60,12 @@
             in IInputContext inputContext);
     boolean inputMethodClientHasFocus(IInputMethodClient client);
 
+    void getInitialDisplaySize(int displayId, out Point size);
+    void getBaseDisplaySize(int displayId, out Point size);
     void setForcedDisplaySize(int displayId, int width, int height);
     void clearForcedDisplaySize(int displayId);
+    int getInitialDisplayDensity(int displayId);
+    int getBaseDisplayDensity(int displayId);
     void setForcedDisplayDensity(int displayId, int density);
     void clearForcedDisplayDensity(int displayId);
 
@@ -171,6 +175,12 @@
     int watchRotation(IRotationWatcher watcher);
 
     /**
+     * Remove a rotation watcher set using watchRotation.
+     * @hide
+     */
+    void removeRotationWatcher(IRotationWatcher watcher);
+
+    /**
      * Determine the preferred edge of the screen to pin the compact options menu against.
      * @return a Gravity value for the options menu panel
      * @hide
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index 523af04..40ee1ad 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -54,6 +54,7 @@
     private native void nativeTransferTo(InputChannel other);
     private native void nativeReadFromParcel(Parcel parcel);
     private native void nativeWriteToParcel(Parcel parcel);
+    private native void nativeDup(InputChannel target);
     
     private native String nativeGetName();
 
@@ -64,7 +65,7 @@
      */
     public InputChannel() {
     }
-    
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -78,7 +79,9 @@
      * Creates a new input channel pair.  One channel should be provided to the input
      * dispatcher and the other to the application's input queue.
      * @param name The descriptive (non-unique) name of the channel pair.
-     * @return A pair of input channels.  They are symmetric and indistinguishable.
+     * @return A pair of input channels.  The first channel is designated as the
+     * server channel and should be used to publish input events.  The second channel
+     * is designated as the client channel and should be used to consume input events.
      */
     public static InputChannel[] openInputChannelPair(String name) {
         if (name == null) {
@@ -123,10 +126,20 @@
         nativeTransferTo(outParameter);
     }
 
+    /**
+     * Duplicates the input channel.
+     */
+    public InputChannel dup() {
+        InputChannel target = new InputChannel();
+        nativeDup(target);
+        return target;
+    }
+
+    @Override
     public int describeContents() {
         return Parcelable.CONTENTS_FILE_DESCRIPTOR;
     }
-    
+
     public void readFromParcel(Parcel in) {
         if (in == null) {
             throw new IllegalArgumentException("in must not be null");
@@ -134,7 +147,8 @@
         
         nativeReadFromParcel(in);
     }
-    
+
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         if (out == null) {
             throw new IllegalArgumentException("out must not be null");
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 3bb9c01..2595ee5 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -62,7 +62,14 @@
      * specify the desired interpretation for its input events.
      */
     public static final int SOURCE_CLASS_MASK = 0x000000ff;
-    
+
+    /**
+     * The input source has no class.
+     *
+     * It is up to the application to determine how to handle the device based on the device type.
+     */
+    public static final int SOURCE_CLASS_NONE = 0x00000000;
+
     /**
      * The input source has buttons or keys.
      * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
@@ -202,6 +209,17 @@
     public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
 
     /**
+     * The input source is a touch device whose motions should be interpreted as navigation events.
+     *
+     * For example, an upward swipe should be as an upward focus traversal in the same manner as
+     * pressing up on a D-Pad would be. Swipes to the left, right and down should be treated in a
+     * similar manner.
+     *
+     * @see #SOURCE_CLASS_NONE
+     */
+    public static final int SOURCE_TOUCH_NAVIGATION = 0x00200000 | SOURCE_CLASS_NONE;
+
+    /**
      * The input source is a joystick.
      * (It may also be a {@link #SOURCE_GAMEPAD}).
      *
@@ -353,8 +371,8 @@
             if (axis < 0) {
                 break;
             }
-            addMotionRange(axis, in.readInt(),
-                    in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+            addMotionRange(axis, in.readInt(), in.readFloat(), in.readFloat(), in.readFloat(),
+                    in.readFloat(), in.readFloat());
         }
     }
 
@@ -566,8 +584,8 @@
 
     // Called from native code.
     private void addMotionRange(int axis, int source,
-            float min, float max, float flat, float fuzz) {
-        mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
+            float min, float max, float flat, float fuzz, float resolution) {
+        mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz, resolution));
     }
 
     /**
@@ -607,14 +625,17 @@
         private float mMax;
         private float mFlat;
         private float mFuzz;
+        private float mResolution;
 
-        private MotionRange(int axis, int source, float min, float max, float flat, float fuzz) {
+        private MotionRange(int axis, int source, float min, float max, float flat, float fuzz,
+                float resolution) {
             mAxis = axis;
             mSource = source;
             mMin = min;
             mMax = max;
             mFlat = flat;
             mFuzz = fuzz;
+            mResolution = resolution;
         }
 
         /**
@@ -633,6 +654,19 @@
             return mSource;
         }
 
+
+        /**
+         * Determines whether the event is from the given source.
+         *
+         * @param source The input source to check against. This can be a specific device type,
+         * such as {@link InputDevice#SOURCE_TOUCH_NAVIGATION}, or a more generic device class,
+         * such as {@link InputDevice#SOURCE_CLASS_POINTER}.
+         * @return Whether the event is from the given source.
+         */
+        public boolean isFromSource(int source) {
+            return (getSource() & source) == source;
+        }
+
         /**
          * Gets the inclusive minimum value for the axis.
          * @return The inclusive minimum value.
@@ -680,6 +714,14 @@
         public float getFuzz() {
             return mFuzz;
         }
+
+        /**
+         * Gets the resolution for input device measurements with respect to this axis.
+         * @return The resolution in units per millimeter, or units per radian for rotational axes.
+         */
+        public float getResolution() {
+            return mResolution;
+        }
     }
 
     @Override
@@ -703,6 +745,7 @@
             out.writeFloat(range.mMax);
             out.writeFloat(range.mFlat);
             out.writeFloat(range.mFuzz);
+            out.writeFloat(range.mResolution);
         }
         out.writeInt(-1);
     }
@@ -757,6 +800,7 @@
             description.append(" max=").append(range.mMax);
             description.append(" flat=").append(range.mFlat);
             description.append(" fuzz=").append(range.mFuzz);
+            description.append(" resolution=").append(range.mResolution);
             description.append("\n");
         }
         return description.toString();
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
index ef810a3..24c3128 100644
--- a/core/java/android/view/InputEvent.java
+++ b/core/java/android/view/InputEvent.java
@@ -83,6 +83,18 @@
     public abstract void setSource(int source);
 
     /**
+     * Determines whether the event is from the given source.
+     *
+     * @param source The input source to check against. This can be a specific device type, such as
+     * {@link InputDevice#SOURCE_TOUCH_NAVIGATION}, or a more generic device class, such as
+     * {@link InputDevice#SOURCE_CLASS_POINTER}.
+     * @return Whether the event is from the given source.
+     */
+    public boolean isFromSource(int source) {
+        return (getSource() & source) == source;
+    }
+
+    /**
      * Copies the event.
      *
      * @return A deep copy of the event.
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 117c101..f5ee7ed 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -23,6 +23,8 @@
 import android.util.Log;
 import android.util.SparseIntArray;
 
+import java.lang.ref.WeakReference;
+
 /**
  * Provides a low-level mechanism for an application to receive input events.
  * @hide
@@ -42,7 +44,7 @@
     // Map from InputEvent sequence numbers to dispatcher sequence numbers.
     private final SparseIntArray mSeqMap = new SparseIntArray();
 
-    private static native int nativeInit(InputEventReceiver receiver,
+    private static native int nativeInit(WeakReference<InputEventReceiver> receiver,
             InputChannel inputChannel, MessageQueue messageQueue);
     private static native void nativeDispose(int receiverPtr);
     private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled);
@@ -65,7 +67,8 @@
 
         mInputChannel = inputChannel;
         mMessageQueue = looper.getQueue();
-        mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue);
+        mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
+                inputChannel, mMessageQueue);
 
         mCloseGuard.open("dispose");
     }
diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java
new file mode 100644
index 0000000..be6a623
--- /dev/null
+++ b/core/java/android/view/InputEventSender.java
@@ -0,0 +1,143 @@
+/*
+ * 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.view;
+
+import dalvik.system.CloseGuard;
+
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Provides a low-level mechanism for an application to send input events.
+ * @hide
+ */
+public abstract class InputEventSender {
+    private static final String TAG = "InputEventSender";
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private int mSenderPtr;
+
+    // We keep references to the input channel and message queue objects here so that
+    // they are not GC'd while the native peer of the receiver is using them.
+    private InputChannel mInputChannel;
+    private MessageQueue mMessageQueue;
+
+    private static native int nativeInit(WeakReference<InputEventSender> sender,
+            InputChannel inputChannel, MessageQueue messageQueue);
+    private static native void nativeDispose(int senderPtr);
+    private static native boolean nativeSendKeyEvent(int senderPtr, int seq, KeyEvent event);
+    private static native boolean nativeSendMotionEvent(int senderPtr, int seq, MotionEvent event);
+
+    /**
+     * Creates an input event sender bound to the specified input channel.
+     *
+     * @param inputChannel The input channel.
+     * @param looper The looper to use when invoking callbacks.
+     */
+    public InputEventSender(InputChannel inputChannel, Looper looper) {
+        if (inputChannel == null) {
+            throw new IllegalArgumentException("inputChannel must not be null");
+        }
+        if (looper == null) {
+            throw new IllegalArgumentException("looper must not be null");
+        }
+
+        mInputChannel = inputChannel;
+        mMessageQueue = looper.getQueue();
+        mSenderPtr = nativeInit(new WeakReference<InputEventSender>(this),
+                inputChannel, mMessageQueue);
+
+        mCloseGuard.open("dispose");
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            dispose(true);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Disposes the receiver.
+     */
+    public void dispose() {
+        dispose(false);
+    }
+
+    private void dispose(boolean finalized) {
+        if (mCloseGuard != null) {
+            if (finalized) {
+                mCloseGuard.warnIfOpen();
+            }
+            mCloseGuard.close();
+        }
+
+        if (mSenderPtr != 0) {
+            nativeDispose(mSenderPtr);
+            mSenderPtr = 0;
+        }
+        mInputChannel = null;
+        mMessageQueue = null;
+    }
+
+    /**
+     * Called when an input event is finished.
+     *
+     * @param seq The input event sequence number.
+     * @param handled True if the input event was handled.
+     */
+    public void onInputEventFinished(int seq, boolean handled) {
+    }
+
+    /**
+     * Sends an input event.
+     * Must be called on the same Looper thread to which the sender is attached.
+     *
+     * @param seq The input event sequence number.
+     * @param event The input event to send.
+     * @return True if the entire event was sent successfully.  May return false
+     * if the input channel buffer filled before all samples were dispatched.
+     */
+    public final boolean sendInputEvent(int seq, InputEvent event) {
+        if (event == null) {
+            throw new IllegalArgumentException("event must not be null");
+        }
+        if (mSenderPtr == 0) {
+            Log.w(TAG, "Attempted to send an input event but the input event "
+                    + "sender has already been disposed.");
+            return false;
+        }
+
+        if (event instanceof KeyEvent) {
+            return nativeSendKeyEvent(mSenderPtr, seq, (KeyEvent)event);
+        } else {
+            return nativeSendMotionEvent(mSenderPtr, seq, (MotionEvent)event);
+        }
+    }
+
+    // Called from native code.
+    @SuppressWarnings("unused")
+    private void dispatchInputEventFinished(int seq, boolean handled) {
+        onInputEventFinished(seq, handled);
+    }
+}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 26a5b26..85695fc 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -19,6 +19,7 @@
 import android.graphics.Canvas;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Trace;
 import android.widget.FrameLayout;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -423,6 +424,8 @@
      */
     public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
         synchronized (mConstructorArgs) {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
+
             final AttributeSet attrs = Xml.asAttributeSet(parser);
             Context lastContext = (Context)mConstructorArgs[0];
             mConstructorArgs[0] = mContext;
@@ -520,6 +523,8 @@
                 mConstructorArgs[1] = null;
             }
 
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+
             return result;
         }
     }
@@ -547,6 +552,8 @@
         Class<? extends View> clazz = null;
 
         try {
+            Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
+
             if (constructor == null) {
                 // Class not found in the cache, see if it's real, and try to add it
                 clazz = mContext.getClassLoader().loadClass(
@@ -615,6 +622,8 @@
                     + (clazz == null ? "<unknown>" : clazz.getName()));
             ie.initCause(e);
             throw ie;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
     }
 
diff --git a/core/java/android/view/SimulatedDpad.java b/core/java/android/view/SimulatedDpad.java
deleted file mode 100644
index 883fd49..0000000
--- a/core/java/android/view/SimulatedDpad.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * 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.view;
-
-import android.app.SearchManager;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.util.Log;
-
-/**
- * This class creates DPAD events from touchpad events.
- * 
- * @see ViewRootImpl
- */
-
-//TODO: Make this class an internal class of ViewRootImpl.java
-class SimulatedDpad {
-
-    private static final String TAG = "SimulatedDpad";
-
-    // Maximum difference in milliseconds between the down and up of a touch
-    // event for it to be considered a tap
-    // TODO:Read this value from a configuration file
-    private static final int MAX_TAP_TIME = 250;
-    // Where the cutoff is for determining an edge swipe
-    private static final float EDGE_SWIPE_THRESHOLD = 0.9f;
-    private static final int MSG_FLICK = 313;
-    // TODO: Pass touch slop from the input device
-    private static final int TOUCH_SLOP = 30;
-    // The position of the previous touchpad event
-    private float mLastTouchpadXPosition;
-    private float mLastTouchpadYPosition;
-    // Where the touchpad was initially pressed
-    private float mTouchpadEnterXPosition;
-    private float mTouchpadEnterYPosition;
-    // When the most recent ACTION_HOVER_ENTER occurred
-    private long mLastTouchPadStartTimeMs = 0;
-    // When the most recent direction key was sent
-    private long mLastTouchPadKeySendTimeMs = 0;
-    // When the most recent touch event of any type occurred
-    private long mLastTouchPadEventTimeMs = 0;
-    // Did the swipe begin in a valid region
-    private boolean mEdgeSwipePossible;
-
-    private final Context mContext;
-
-    // How quickly keys were sent;
-    private int mKeySendRateMs = 0;
-    private int mLastKeySent;
-    // Last movement in device screen pixels
-    private float mLastMoveX = 0;
-    private float mLastMoveY = 0;
-    // Offset from the initial touch. Gets reset as direction keys are sent.
-    private float mAccumulatedX;
-    private float mAccumulatedY;
-
-    // Change in position allowed during tap events
-    private float mTouchSlop;
-    private float mTouchSlopSquared;
-    // Has the TouchSlop constraint been invalidated
-    private boolean mAlwaysInTapRegion = true;
-
-    // Information from the most recent event.
-    // Used to determine what device sent the event during a fling.
-    private int mLastSource;
-    private int mLastMetaState;
-    private int mLastDeviceId;
-
-    // TODO: Currently using screen dimensions tuned to a Galaxy Nexus, need to
-    // read this from a config file instead
-    private int mDistancePerTick;
-    private int mDistancePerTickSquared;
-    // Highest rate that the flinged events can occur at before dying out
-    private int mMaxRepeatDelay;
-    // The square of the minimum distance needed for a flick to register
-    private int mMinFlickDistanceSquared;
-    // How quickly the repeated events die off
-    private float mFlickDecay;
-
-    public SimulatedDpad(Context context) {
-        mDistancePerTick = SystemProperties.getInt("persist.vr_dist_tick", 64);
-        mDistancePerTickSquared = mDistancePerTick * mDistancePerTick;
-        mMaxRepeatDelay = SystemProperties.getInt("persist.vr_repeat_delay", 300);
-        mMinFlickDistanceSquared = SystemProperties.getInt("persist.vr_min_flick", 20);
-        mMinFlickDistanceSquared *= mMinFlickDistanceSquared;
-        mFlickDecay = Float.parseFloat(SystemProperties.get(
-                "persist.sys.vr_flick_decay", "1.3"));
-        mTouchSlop = TOUCH_SLOP;
-        mTouchSlopSquared = mTouchSlop * mTouchSlop;
-
-        mContext = context;
-    }
-
-    private final Handler mHandler = new Handler(true /*async*/) {
-            @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_FLICK: {
-                    final long time = SystemClock.uptimeMillis();
-                    ViewRootImpl viewroot = (ViewRootImpl) msg.obj;
-                    // Send the key
-                    viewroot.enqueueInputEvent(new KeyEvent(time, time,
-                            KeyEvent.ACTION_DOWN, msg.arg2, 0, mLastMetaState,
-                            mLastDeviceId, 0, KeyEvent.FLAG_FALLBACK, mLastSource));
-                    viewroot.enqueueInputEvent(new KeyEvent(time, time,
-                            KeyEvent.ACTION_UP, msg.arg2, 0, mLastMetaState,
-                            mLastDeviceId, 0, KeyEvent.FLAG_FALLBACK, mLastSource));
-
-                    // Increase the delay by the decay factor and resend
-                    final int delay = (int) Math.ceil(mFlickDecay * msg.arg1);
-                    if (delay <= mMaxRepeatDelay) {
-                        Message msgCopy = Message.obtain(msg);
-                        msgCopy.arg1 = delay;
-                        msgCopy.setAsynchronous(true);
-                        mHandler.sendMessageDelayed(msgCopy, delay);
-                    }
-                    break;
-                }
-            }
-        }
-    };
-
-    public void updateTouchPad(ViewRootImpl viewroot, MotionEvent event,
-            boolean synthesizeNewKeys) {
-        if (!synthesizeNewKeys) {
-            mHandler.removeMessages(MSG_FLICK);
-        }
-        InputDevice device = event.getDevice();
-        if (device == null) {
-            return;
-        }
-        // Store what time the touchpad event occurred
-        final long time = SystemClock.uptimeMillis();
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                mLastTouchPadStartTimeMs = time;
-                mAlwaysInTapRegion = true;
-                mTouchpadEnterXPosition = event.getX();
-                mTouchpadEnterYPosition = event.getY();
-                mAccumulatedX = 0;
-                mAccumulatedY = 0;
-                mLastMoveX = 0;
-                mLastMoveY = 0;
-                if (device.getMotionRange(MotionEvent.AXIS_Y).getMax()
-                        * EDGE_SWIPE_THRESHOLD < event.getY()) {
-                    // Did the swipe begin in a valid region
-                    mEdgeSwipePossible = true;
-                }
-                // Clear any flings
-                if (synthesizeNewKeys) {
-                    mHandler.removeMessages(MSG_FLICK);
-                }
-                break;
-            case MotionEvent.ACTION_MOVE:
-                // Determine whether the move is slop or an intentional move
-                float deltaX = event.getX() - mTouchpadEnterXPosition;
-                float deltaY = event.getY() - mTouchpadEnterYPosition;
-                if (mTouchSlopSquared < deltaX * deltaX + deltaY * deltaY) {
-                    mAlwaysInTapRegion = false;
-                }
-                // Checks if the swipe has crossed the midpoint
-                // and if our swipe gesture is complete
-                if (event.getY() < (device.getMotionRange(MotionEvent.AXIS_Y).getMax()
-                        * .5) && mEdgeSwipePossible) {
-                    mEdgeSwipePossible = false;
-
-                    Intent intent =
-                            ((SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE))
-                            .getAssistIntent(mContext, false, UserHandle.USER_CURRENT_OR_SELF);
-                    if (intent != null) {
-                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                        try {
-                            mContext.startActivity(intent);
-                        } catch (ActivityNotFoundException e){
-                            Log.e(TAG, "Could not start search activity");
-                        }
-                    } else {
-                        Log.e(TAG, "Could not find a search activity");
-                    }
-                }
-                // Find the difference in position between the two most recent
-                // touchpad events
-                mLastMoveX = event.getX() - mLastTouchpadXPosition;
-                mLastMoveY = event.getY() - mLastTouchpadYPosition;
-                mAccumulatedX += mLastMoveX;
-                mAccumulatedY += mLastMoveY;
-                float mAccumulatedXSquared = mAccumulatedX * mAccumulatedX;
-                float mAccumulatedYSquared = mAccumulatedY * mAccumulatedY;
-                // Determine if we've moved far enough to send a key press
-                if (mAccumulatedXSquared > mDistancePerTickSquared ||
-                        mAccumulatedYSquared > mDistancePerTickSquared) {
-                    float dominantAxis;
-                    float sign;
-                    boolean isXAxis;
-                    int key;
-                    int repeatCount = 0;
-                    // Determine dominant axis
-                    if (mAccumulatedXSquared > mAccumulatedYSquared) {
-                        dominantAxis = mAccumulatedX;
-                        isXAxis = true;
-                    } else {
-                        dominantAxis = mAccumulatedY;
-                        isXAxis = false;
-                    }
-                    // Determine sign of axis
-                    sign = (dominantAxis > 0) ? 1 : -1;
-                    // Determine key to send
-                    if (isXAxis) {
-                        key = (sign == 1) ? KeyEvent.KEYCODE_DPAD_RIGHT :
-                                KeyEvent.KEYCODE_DPAD_LEFT;
-                    } else {
-                        key = (sign == 1) ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
-                    }
-                    // Send key until maximum distance constraint is satisfied
-                    while (dominantAxis * dominantAxis > mDistancePerTickSquared) {
-                        repeatCount++;
-                        dominantAxis -= sign * mDistancePerTick;
-                        if (synthesizeNewKeys) {
-                            viewroot.enqueueInputEvent(new KeyEvent(time, time,
-                                    KeyEvent.ACTION_DOWN, key, 0, event.getMetaState(),
-                                    event.getDeviceId(), 0, KeyEvent.FLAG_FALLBACK,
-                                    event.getSource()));
-                            viewroot.enqueueInputEvent(new KeyEvent(time, time,
-                                    KeyEvent.ACTION_UP, key, 0, event.getMetaState(),
-                                    event.getDeviceId(), 0, KeyEvent.FLAG_FALLBACK,
-                                    event.getSource()));
-                        }
-                    }
-                    // Save new axis values
-                    mAccumulatedX = isXAxis ? dominantAxis : 0;
-                    mAccumulatedY = isXAxis ? 0 : dominantAxis;
-
-                    mLastKeySent = key;
-                    mKeySendRateMs = (int) ((time - mLastTouchPadKeySendTimeMs) / repeatCount);
-                    mLastTouchPadKeySendTimeMs = time;
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-                if (time - mLastTouchPadStartTimeMs < MAX_TAP_TIME && mAlwaysInTapRegion) {
-                    if (synthesizeNewKeys) {
-                        viewroot.enqueueInputEvent(new KeyEvent(mLastTouchPadStartTimeMs, time,
-                                KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0,
-                                event.getMetaState(), event.getDeviceId(), 0,
-                                KeyEvent.FLAG_FALLBACK, event.getSource()));
-                        viewroot.enqueueInputEvent(new KeyEvent(mLastTouchPadStartTimeMs, time,
-                                KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0,
-                                event.getMetaState(), event.getDeviceId(), 0,
-                                KeyEvent.FLAG_FALLBACK, event.getSource()));
-                    }
-                } else {
-                    float xMoveSquared = mLastMoveX * mLastMoveX;
-                    float yMoveSquared = mLastMoveY * mLastMoveY;
-                    // Determine whether the last gesture was a fling.
-                    if (mMinFlickDistanceSquared <= xMoveSquared + yMoveSquared &&
-                            time - mLastTouchPadEventTimeMs <= MAX_TAP_TIME &&
-                            mKeySendRateMs <= mMaxRepeatDelay && mKeySendRateMs > 0) {
-                        mLastDeviceId = event.getDeviceId();
-                        mLastSource = event.getSource();
-                        mLastMetaState = event.getMetaState();
-
-                        if (synthesizeNewKeys) {
-                            Message message = Message.obtain(mHandler, MSG_FLICK,
-                                    mKeySendRateMs, mLastKeySent, viewroot);
-                            message.setAsynchronous(true);
-                            mHandler.sendMessageDelayed(message, mKeySendRateMs);
-                        }
-                    }
-                }
-                mEdgeSwipePossible = false;
-                break;
-        }
-
-        // Store touch event position and time
-        mLastTouchPadEventTimeMs = time;
-        mLastTouchpadXPosition = event.getX();
-        mLastTouchpadYPosition = event.getY();
-    }
-}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 9955bc1..edfef56 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -39,7 +39,6 @@
     private native void nativeUnlockCanvasAndPost(int nativeObject, Canvas canvas);
 
     private static native void nativeRelease(int nativeObject);
-    private static native void nativeDestroy(int nativeObject);
     private static native boolean nativeIsValid(int nativeObject);
     private static native boolean nativeIsConsumerRunningBehind(int nativeObject);
     private static native int nativeCopyFrom(int nativeObject, int surfaceControlNativeObject);
@@ -73,6 +72,9 @@
     // mNativeSurface.
     int mNativeObject; // package scope only for SurfaceControl access
 
+    // protects the native state
+    private final Object mNativeObjectLock = new Object();
+
     private int mGenerationId; // incremented each time mNativeSurface changes
     @SuppressWarnings("UnusedDeclaration")
     private final Canvas mCanvas = new CompatibleCanvas();
@@ -106,7 +108,6 @@
      * @hide
      */
     public Surface() {
-        mCloseGuard.open("release");
     }
 
     /**
@@ -135,6 +136,7 @@
         mCloseGuard.open("release");
     }
 
+    /* called from android_view_Surface_createFromIGraphicBufferProducer() */
     private Surface(int nativeObject) {
         mNativeObject = nativeObject;
         mCloseGuard.open("release");
@@ -146,9 +148,7 @@
             if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
             }
-            if (mNativeObject != 0) {
-                nativeRelease(mNativeObject);
-            }
+            release();
         } finally {
             super.finalize();
         }
@@ -160,12 +160,14 @@
      * This will make the surface invalid.
      */
     public void release() {
-        if (mNativeObject != 0) {
-            nativeRelease(mNativeObject);
-            mNativeObject = 0;
-            mGenerationId++;
+        synchronized (mNativeObjectLock) {
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
+                mNativeObject = 0;
+                mGenerationId++;
+            }
+            mCloseGuard.close();
         }
-        mCloseGuard.close();
     }
 
     /**
@@ -175,12 +177,7 @@
      * @hide
      */
     public void destroy() {
-        if (mNativeObject != 0) {
-            nativeDestroy(mNativeObject);
-            mNativeObject = 0;
-            mGenerationId++;
-        }
-        mCloseGuard.close();
+        release();
     }
 
     /**
@@ -190,8 +187,10 @@
      * Otherwise returns false.
      */
     public boolean isValid() {
-        if (mNativeObject == 0) return false;
-        return nativeIsValid(mNativeObject);
+        synchronized (mNativeObjectLock) {
+            if (mNativeObject == 0) return false;
+            return nativeIsValid(mNativeObject);
+        }
     }
 
     /**
@@ -212,8 +211,10 @@
      * @hide
      */
     public boolean isConsumerRunningBehind() {
-        checkNotReleased();
-        return nativeIsConsumerRunningBehind(mNativeObject);
+        synchronized (mNativeObjectLock) {
+            checkNotReleasedLocked();
+            return nativeIsConsumerRunningBehind(mNativeObject);
+        }
     }
 
     /**
@@ -233,8 +234,10 @@
      */
     public Canvas lockCanvas(Rect inOutDirty)
             throws OutOfResourcesException, IllegalArgumentException {
-        checkNotReleased();
-        return nativeLockCanvas(mNativeObject, inOutDirty);
+        synchronized (mNativeObjectLock) {
+            checkNotReleasedLocked();
+            return nativeLockCanvas(mNativeObject, inOutDirty);
+        }
     }
 
     /**
@@ -244,8 +247,10 @@
      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
      */
     public void unlockCanvasAndPost(Canvas canvas) {
-        checkNotReleased();
-        nativeUnlockCanvasAndPost(mNativeObject, canvas);
+        synchronized (mNativeObjectLock) {
+            checkNotReleasedLocked();
+            nativeUnlockCanvasAndPost(mNativeObject, canvas);
+        }
     }
 
     /** 
@@ -286,33 +291,43 @@
             throw new NullPointerException(
                     "SurfaceControl native object is null. Are you using a released SurfaceControl?");
         }
-        mNativeObject = nativeCopyFrom(mNativeObject, other.mNativeObject);
-        mGenerationId++;
+        synchronized (mNativeObjectLock) {
+            mNativeObject = nativeCopyFrom(mNativeObject, other.mNativeObject);
+            if (mNativeObject == 0) {
+                // nativeCopyFrom released our reference
+                mCloseGuard.close();
+            }
+            mGenerationId++;
+        }
     }
 
     /**
-     * Transfer the native state from 'other' to this surface, releasing it
-     * from 'other'.  This is for use in the client side for drawing into a
-     * surface; not guaranteed to work on the window manager side.
-     * This is for use by the client to move the underlying surface from
-     * one Surface object to another, in particular in SurfaceFlinger.
-     * @hide.
+     * This is intended to be used by {@link SurfaceView.updateWindow} only.
+     * @param other access is not thread safe
+     * @hide
+     * @deprecated
      */
+    @Deprecated
     public void transferFrom(Surface other) {
         if (other == null) {
             throw new IllegalArgumentException("other must not be null");
         }
         if (other != this) {
-            if (mNativeObject != 0) {
-                // release our reference to our native object
-                nativeRelease(mNativeObject);
+            synchronized (mNativeObjectLock) {
+                if (mNativeObject != 0) {
+                    // release our reference to our native object
+                    nativeRelease(mNativeObject);
+                }
+                // transfer the reference from other to us
+                if (other.mNativeObject != 0 && mNativeObject == 0) {
+                    mCloseGuard.open("release");
+                }
+                mNativeObject = other.mNativeObject;
+                mGenerationId++;
             }
-            // transfer the reference from other to us
-            mNativeObject = other.mNativeObject;
-            mGenerationId++;
-
             other.mNativeObject = 0;
             other.mGenerationId++;
+            other.mCloseGuard.close();
         }
     }
 
@@ -325,9 +340,15 @@
         if (source == null) {
             throw new IllegalArgumentException("source must not be null");
         }
-        mName = source.readString();
-        mNativeObject = nativeReadFromParcel(mNativeObject, source);
-        mGenerationId++;
+        synchronized (mNativeObjectLock) {
+            mName = source.readString();
+            int nativeObject = nativeReadFromParcel(mNativeObject, source);
+            if (nativeObject !=0 && mNativeObject == 0) {
+                mCloseGuard.open("release");
+            }
+            mNativeObject = nativeObject;
+            mGenerationId++;
+        }
     }
 
     @Override
@@ -335,8 +356,10 @@
         if (dest == null) {
             throw new IllegalArgumentException("dest must not be null");
         }
-        dest.writeString(mName);
-        nativeWriteToParcel(mNativeObject, dest);
+        synchronized (mNativeObjectLock) {
+            dest.writeString(mName);
+            nativeWriteToParcel(mNativeObject, dest);
+        }
         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
             release();
         }
@@ -429,7 +452,7 @@
         }
     }
 
-    private void checkNotReleased() {
+    private void checkNotReleasedLocked() {
         if (mNativeObject == 0) throw new NullPointerException(
                 "mNativeObject is null. Have you called release() already?");
     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index df07dcd..e869d09 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -574,7 +574,8 @@
      * @param maxLayer The highest (top-most Z order) surface layer to
      * include in the screenshot.
      * @return Returns a Bitmap containing the screen contents, or null
-     * if an error occurs.
+     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
+     * possible, once its content is not needed anymore.
      */
     public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
         // TODO: should take the display as a parameter
@@ -586,6 +587,14 @@
     /**
      * Like {@link SurfaceControl#screenshot(int, int, int, int)} but includes all
      * Surfaces in the screenshot.
+     *
+     * @param width The desired width of the returned bitmap; the raw
+     * screen will be scaled down to this size.
+     * @param height The desired height of the returned bitmap; the raw
+     * screen will be scaled down to this size.
+     * @return Returns a Bitmap containing the screen contents, or null
+     * if an error occurs. Make sure to call Bitmap.recycle() as soon as
+     * possible, once its content is not needed anymore.
      */
     public static Bitmap screenshot(int width, int height) {
         // TODO: should take the display as a parameter
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7e0d115..7c82f7e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3223,6 +3223,12 @@
     AccessibilityDelegate mAccessibilityDelegate;
 
     /**
+     * The view's overlay layer. Developers get a reference to the overlay via getOverlay()
+     * and add/remove objects to/from the overlay directly through the Overlay methods.
+     */
+    ViewOverlay mOverlay;
+
+    /**
      * Consistency verifier for debugging purposes.
      * @hide
      */
@@ -5038,7 +5044,8 @@
             }
 
             if ((mAttachInfo.mAccessibilityFetchFlags
-                    & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0) {
+                    & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0
+                    && Resources.resourceHasPackage(mID)) {
                 try {
                     String viewId = getResources().getResourceName(mID);
                     info.setViewIdResourceName(viewId);
@@ -6068,8 +6075,7 @@
             mTransientStateCount = 0;
             Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " +
                     "unmatched pair of setHasTransientState calls");
-        }
-        if ((hasTransientState && mTransientStateCount == 1) ||
+        } else if ((hasTransientState && mTransientStateCount == 1) ||
                 (!hasTransientState && mTransientStateCount == 0)) {
             // update flag if we've just incremented up from 0 or decremented down to 0
             mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) |
@@ -6883,7 +6889,7 @@
     /**
      * Adds the children of a given View for accessibility. Since some Views are
      * not important for accessibility the children for accessibility are not
-     * necessarily direct children of the riew, rather they are the first level of
+     * necessarily direct children of the view, rather they are the first level of
      * descendants important for accessibility.
      *
      * @param children The list of children for accessibility.
@@ -8112,13 +8118,13 @@
      * delivered to the focused view.
      * </p>
      * <pre> public boolean onGenericMotionEvent(MotionEvent event) {
-     *     if ((event.getSource() &amp; InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+     *     if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) {
      *         if (event.getAction() == MotionEvent.ACTION_MOVE) {
      *             // process the joystick movement...
      *             return true;
      *         }
      *     }
-     *     if ((event.getSource() &amp; InputDevice.SOURCE_CLASS_POINTER) != 0) {
+     *     if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
      *         switch (event.getAction()) {
      *             case MotionEvent.ACTION_HOVER_MOVE:
      *                 // process the mouse hover movement...
@@ -9479,17 +9485,26 @@
      * <p>Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
      * completely transparent and 1 means the view is completely opaque.</p>
      *
-     * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
-     * responsible for applying the opacity itself. Otherwise, calling this method is
-     * equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
-     * setting a hardware layer.</p>
+     * <p> Note that setting alpha to a translucent value (0 < alpha < 1) can have significant
+     * performance implications, especially for large views. It is best to use the alpha property
+     * sparingly and transiently, as in the case of fading animations.</p>
      *
-     * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have
-     * performance implications. It is generally best to use the alpha property sparingly and
-     * transiently, as in the case of fading animations.</p>
+     * <p>For a view with a frequently changing alpha, such as during a fading animation, it is
+     * strongly recommended for performance reasons to either override
+     * {@link #hasOverlappingRendering()} to return false if appropriate, or setting a
+     * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view.</p>
+     *
+     * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
+     * responsible for applying the opacity itself.</p>
+     *
+     * <p>Note that if the view is backed by a
+     * {@link #setLayerType(int, android.graphics.Paint) layer} and is associated with a
+     * {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an alpha value less than
+     * 1.0 will supercede the alpha of the layer paint.</p>
      *
      * @param alpha The opacity of the view.
      *
+     * @see #hasOverlappingRendering()
      * @see #setLayerType(int, android.graphics.Paint)
      *
      * @attr ref android.R.styleable#View_alpha
@@ -9589,7 +9604,7 @@
                 mDisplayList.setTop(mTop);
             }
 
-            onSizeChanged(width, mBottom - mTop, width, oldHeight);
+            sizeChange(width, mBottom - mTop, width, oldHeight);
 
             if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
@@ -9662,7 +9677,7 @@
                 mDisplayList.setBottom(mBottom);
             }
 
-            onSizeChanged(width, mBottom - mTop, width, oldHeight);
+            sizeChange(width, mBottom - mTop, width, oldHeight);
 
             if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
@@ -9729,7 +9744,7 @@
                 mDisplayList.setLeft(left);
             }
 
-            onSizeChanged(mRight - mLeft, height, oldWidth, height);
+            sizeChange(mRight - mLeft, height, oldWidth, height);
 
             if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
@@ -9793,7 +9808,7 @@
                 mDisplayList.setRight(mRight);
             }
 
-            onSizeChanged(mRight - mLeft, height, oldWidth, height);
+            sizeChange(mRight - mLeft, height, oldWidth, height);
 
             if (!matrixIsIdentity) {
                 if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
@@ -10642,7 +10657,7 @@
         // Opaque if:
         //   - Has a background
         //   - Background is opaque
-        //   - Doesn't have scrollbars or scrollbars are inside overlay
+        //   - Doesn't have scrollbars or scrollbars overlay
 
         if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
             mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND;
@@ -10652,7 +10667,8 @@
 
         final int flags = mViewFlags;
         if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
-                (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY) {
+                (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY ||
+                (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) {
             mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS;
         } else {
             mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS;
@@ -11552,7 +11568,10 @@
                 final int scrollY = mScrollY;
                 final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
 
-                int left, top, right, bottom;
+                int left;
+                int top;
+                int right;
+                int bottom;
 
                 if (drawHorizontalScrollBar) {
                     int size = scrollBar.getSize(false);
@@ -12087,6 +12106,9 @@
     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
         //System.out.println("Attached! " + this);
         mAttachInfo = info;
+        if (mOverlay != null) {
+            mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
+        }
         mWindowAttachCount++;
         // We will need to evaluate the drawable state at least once.
         mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
@@ -12155,6 +12177,9 @@
         }
 
         mAttachInfo = null;
+        if (mOverlay != null) {
+            mOverlay.getOverlayView().dispatchDetachedFromWindow();
+        }
     }
 
     /**
@@ -12349,13 +12374,11 @@
      * </ul>
      *
      * <p>If this view has an alpha value set to < 1.0 by calling
-     * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
-     * this view's alpha value. Calling {@link #setAlpha(float)} is therefore
-     * equivalent to setting a hardware layer on this view and providing a paint with
-     * the desired alpha value.</p>
+     * {@link #setAlpha(float)}, the alpha value of the layer's paint is superceded
+     * by this view's alpha value.</p>
      *
-     * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
-     * {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
+     * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE},
+     * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE}
      * for more information on when and how to use layers.</p>
      *
      * @param layerType The type of layer to use with this view, must be one of
@@ -12425,11 +12448,8 @@
      * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
      * </ul>
      *
-     * <p>If this view has an alpha value set to < 1.0 by calling
-     * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
-     * this view's alpha value. Calling {@link #setAlpha(float)} is therefore
-     * equivalent to setting a hardware layer on this view and providing a paint with
-     * the desired alpha value.</p>
+     * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the
+     * alpha value of the layer's paint is superceded by this view's alpha value.</p>
      *
      * @param paint The paint used to compose the layer. This argument is optional
      *        and can be null. It is ignored when the layer type is
@@ -12810,6 +12830,9 @@
                     // Fast path for layouts with no backgrounds
                     if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                         dispatchDraw(canvas);
+                        if (mOverlay != null && !mOverlay.isEmpty()) {
+                            mOverlay.getOverlayView().draw(canvas);
+                        }
                     } else {
                         draw(canvas);
                     }
@@ -13123,6 +13146,9 @@
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                 mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                 dispatchDraw(canvas);
+                if (mOverlay != null && !mOverlay.isEmpty()) {
+                    mOverlay.getOverlayView().draw(canvas);
+                }
             } else {
                 draw(canvas);
             }
@@ -13878,6 +13904,10 @@
             // Step 6, draw decorations (scrollbars)
             onDrawScrollBars(canvas);
 
+            if (mOverlay != null && !mOverlay.isEmpty()) {
+                mOverlay.getOverlayView().dispatchDraw(canvas);
+            }
+
             // we're done...
             return;
         }
@@ -14017,6 +14047,31 @@
 
         // Step 6, draw decorations (scrollbars)
         onDrawScrollBars(canvas);
+
+        if (mOverlay != null && !mOverlay.isEmpty()) {
+            mOverlay.getOverlayView().dispatchDraw(canvas);
+        }
+    }
+
+    /**
+     * Returns the overlay for this view, creating it if it does not yet exist.
+     * Adding drawables to the overlay will cause them to be displayed whenever
+     * the view itself is redrawn. Objects in the overlay should be actively
+     * managed: remove them when they should not be displayed anymore. The
+     * overlay will always have the same size as its host view.
+     *
+     * <p>Note: Overlays do not currently work correctly with {@link
+     * SurfaceView} or {@link TextureView}; contents in overlays for these
+     * types of views may not display correctly.</p>
+     *
+     * @return The ViewOverlay object for this view.
+     * @see ViewOverlay
+     */
+    public ViewOverlay getOverlay() {
+        if (mOverlay == null) {
+            mOverlay = new ViewOverlay(mContext, this);
+        }
+        return mOverlay;
     }
 
     /**
@@ -14272,7 +14327,7 @@
                         mTransformationInfo.mMatrixDirty = true;
                     }
                 }
-                onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
+                sizeChange(newWidth, newHeight, oldWidth, oldHeight);
             }
 
             if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) {
@@ -14296,6 +14351,14 @@
         return changed;
     }
 
+    private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
+        onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
+        if (mOverlay != null) {
+            mOverlay.getOverlayView().setRight(newWidth);
+            mOverlay.getOverlayView().setBottom(newHeight);
+        }
+    }
+
     /**
      * Finalize inflating a view from XML.  This is called as the last phase
      * of inflation, after all child views have been added.
@@ -16925,6 +16988,14 @@
      *
      * @attr ref android.R.styleable#View_textDirection
      */
+    @ViewDebug.ExportedProperty(category = "text", mapping = {
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
+    })
     public int getTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
     }
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 987ff785..40b6a08 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1054,8 +1054,7 @@
                 String categoryPrefix =
                         property.category().length() != 0 ? property.category() + ":" : "";
 
-                if (type == int.class) {
-
+                if (type == int.class || type == byte.class) {
                     if (property.resolveId() && context != null) {
                         final int id = field.getInt(view);
                         fieldValue = resolveId(context, id);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 442dfdb..311d1d0 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -51,6 +51,8 @@
 import java.util.Collections;
 import java.util.HashSet;
 
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
 /**
  * <p>
  * A <code>ViewGroup</code> is a special view that can contain other views
@@ -404,11 +406,17 @@
     private View[] mChildren;
     // Number of valid children in the mChildren array, the rest should be null or not
     // considered as children
-
-    private boolean mLayoutSuppressed = false;
-
     private int mChildrenCount;
 
+    // Whether layout calls are currently being suppressed, controlled by calls to
+    // suppressLayout()
+    boolean mSuppressLayout = false;
+
+    // Whether any layout calls have actually been suppressed while mSuppressLayout
+    // has been true. This tracks whether we need to issue a requestLayout() when
+    // layout is later re-enabled.
+    private boolean mLayoutCalledWhileSuppressed = false;
+
     private static final int ARRAY_INITIAL_CAPACITY = 12;
     private static final int ARRAY_CAPACITY_INCREMENT = 12;
 
@@ -1869,12 +1877,12 @@
                     removePointersFromTouchTargets(idBitsToAssign);
 
                     final int childrenCount = mChildrenCount;
-                    if (childrenCount != 0) {
+                    if (newTouchTarget == null && childrenCount != 0) {
+                        final float x = ev.getX(actionIndex);
+                        final float y = ev.getY(actionIndex);
                         // Find a child that can receive the event.
                         // Scan children from front to back.
                         final View[] children = mChildren;
-                        final float x = ev.getX(actionIndex);
-                        final float y = ev.getY(actionIndex);
 
                         final boolean customOrder = isChildrenDrawingOrderEnabled();
                         for (int i = childrenCount - 1; i >= 0; i--) {
@@ -1936,7 +1944,7 @@
                         handled = true;
                     } else {
                         final boolean cancelChild = resetCancelNextUpFlag(target.child)
-                        || intercepted;
+                                || intercepted;
                         if (dispatchTransformedTouchEvent(ev, cancelChild,
                                 target.child, target.pointerIdBits)) {
                             handled = true;
@@ -2538,7 +2546,7 @@
         exitHoverTargets();
 
         // In case view is detached while transition is running
-        mLayoutSuppressed = false;
+        mLayoutCalledWhileSuppressed = false;
 
         // Tear down our drag tracking
         mDragNotifiedChildren = null;
@@ -2959,6 +2967,30 @@
     }
 
     /**
+     * Returns the ViewGroupOverlay for this view group, creating it if it does
+     * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
+     * {@link ViewGroupOverlay} allows views to be added to the overlay. These
+     * views, like overlay drawables, are visual-only; they do not receive input
+     * events and should not be used as anything other than a temporary
+     * representation of a view in a parent container, such as might be used
+     * by an animation effect.
+     *
+     * <p>Note: Overlays do not currently work correctly with {@link
+     * SurfaceView} or {@link TextureView}; contents in overlays for these
+     * types of views may not display correctly.</p>
+     *
+     * @return The ViewGroupOverlay object for this view.
+     * @see ViewGroupOverlay
+     */
+    @Override
+    public ViewGroupOverlay getOverlay() {
+        if (mOverlay == null) {
+            mOverlay = new ViewGroupOverlay(mContext, this);
+        }
+        return (ViewGroupOverlay) mOverlay;
+    }
+
+    /**
      * Returns the index of the child to draw for this iteration. Override this
      * if you want to change the drawing order of children. By default, it
      * returns i.
@@ -3022,6 +3054,14 @@
                 child.mRecreateDisplayList = false;
             }
         }
+        if (mOverlay != null) {
+            View overlayView = mOverlay.getOverlayView();
+            overlayView.mRecreateDisplayList = (overlayView.mPrivateFlags & PFLAG_INVALIDATED)
+                    == PFLAG_INVALIDATED;
+            overlayView.mPrivateFlags &= ~PFLAG_INVALIDATED;
+            overlayView.getDisplayList();
+            overlayView.mRecreateDisplayList = false;
+        }
     }
 
     /**
@@ -4492,7 +4532,7 @@
             super.layout(l, t, r, b);
         } else {
             // record the fact that we noop'd it; request layout when transition finishes
-            mLayoutSuppressed = true;
+            mLayoutCalledWhileSuppressed = true;
         }
     }
 
@@ -5168,9 +5208,9 @@
         @Override
         public void endTransition(LayoutTransition transition, ViewGroup container,
                 View view, int transitionType) {
-            if (mLayoutSuppressed && !transition.isChangingLayout()) {
+            if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
                 requestLayout();
-                mLayoutSuppressed = false;
+                mLayoutCalledWhileSuppressed = false;
             }
             if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
                 endViewTransition(view);
@@ -5179,6 +5219,24 @@
     };
 
     /**
+     * Tells this ViewGroup to suppress all layout() calls until layout
+     * suppression is disabled with a later call to suppressLayout(false).
+     * When layout suppression is disabled, a requestLayout() call is sent
+     * if layout() was attempted while layout was being suppressed.
+     *
+     * @hide
+     */
+    public void suppressLayout(boolean suppress) {
+        mSuppressLayout = suppress;
+        if (!suppress) {
+            if (mLayoutCalledWhileSuppressed) {
+                requestLayout();
+                mLayoutCalledWhileSuppressed = false;
+            }
+        }
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -5833,7 +5891,7 @@
          * to this field.
          */
         @ViewDebug.ExportedProperty(category = "layout")
-        private int startMargin = DEFAULT_RELATIVE;
+        private int startMargin = DEFAULT_MARGIN_RELATIVE;
 
         /**
          * The end margin in pixels of the child.
@@ -5841,21 +5899,48 @@
          * to this field.
          */
         @ViewDebug.ExportedProperty(category = "layout")
-        private int endMargin = DEFAULT_RELATIVE;
+        private int endMargin = DEFAULT_MARGIN_RELATIVE;
 
         /**
          * The default start and end margin.
          * @hide
          */
-        public static final int DEFAULT_RELATIVE = Integer.MIN_VALUE;
+        public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
 
-        private int initialLeftMargin;
-        private int initialRightMargin;
+        /**
+         * Bit  0: layout direction
+         * Bit  1: layout direction
+         * Bit  2: left margin undefined
+         * Bit  3: right margin undefined
+         * Bit  4: is RTL compatibility mode
+         * Bit  5: need resolution
+         *
+         * Bit 6 to 7 not used
+         *
+         * @hide
+         */
+        @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
+                @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
+                        equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
+                @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
+                        equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
+                @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
+                        equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
+                @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
+                        equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
+                @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
+                        equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
+        })
+        byte mMarginFlags;
 
-        private static int LAYOUT_DIRECTION_UNDEFINED = -1;
+        private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
+        private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
+        private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
+        private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
+        private static final int NEED_RESOLUTION_MASK = 0x00000020;
 
-        // Layout direction undefined by default
-        private int layoutDirection = LAYOUT_DIRECTION_UNDEFINED;
+        private static final int DEFAULT_MARGIN_RESOLVED = 0;
+        private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
 
         /**
          * Creates a new set of layout parameters. The values are extracted from
@@ -5882,21 +5967,47 @@
                 bottomMargin = margin;
             } else {
                 leftMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
-                topMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
+                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
+                        UNDEFINED_MARGIN);
+                if (leftMargin == UNDEFINED_MARGIN) {
+                    mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+                    leftMargin = DEFAULT_MARGIN_RESOLVED;
+                }
                 rightMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
+                        R.styleable.ViewGroup_MarginLayout_layout_marginRight,
+                        UNDEFINED_MARGIN);
+                if (rightMargin == UNDEFINED_MARGIN) {
+                    mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
+                    rightMargin = DEFAULT_MARGIN_RESOLVED;
+                }
+
+                topMargin = a.getDimensionPixelSize(
+                        R.styleable.ViewGroup_MarginLayout_layout_marginTop,
+                        DEFAULT_MARGIN_RESOLVED);
                 bottomMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
+                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
+                        DEFAULT_MARGIN_RESOLVED);
+
                 startMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginStart, DEFAULT_RELATIVE);
+                        R.styleable.ViewGroup_MarginLayout_layout_marginStart,
+                        DEFAULT_MARGIN_RELATIVE);
                 endMargin = a.getDimensionPixelSize(
-                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd, DEFAULT_RELATIVE);
+                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
+                        DEFAULT_MARGIN_RELATIVE);
+
+                if (isMarginRelative()) {
+                   mMarginFlags |= NEED_RESOLUTION_MASK;
+                }
             }
 
-            initialLeftMargin = leftMargin;
-            initialRightMargin = rightMargin;
+            final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
+            final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
+            if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
+                mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
+            }
+
+            // Layout direction is LTR by default
+            mMarginFlags |= LAYOUT_DIRECTION_LTR;
 
             a.recycle();
         }
@@ -5906,6 +6017,12 @@
          */
         public MarginLayoutParams(int width, int height) {
             super(width, height);
+
+            mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+            mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
+
+            mMarginFlags &= ~NEED_RESOLUTION_MASK;
+            mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
         }
 
         /**
@@ -5924,10 +6041,7 @@
             this.startMargin = source.startMargin;
             this.endMargin = source.endMargin;
 
-            this.initialLeftMargin = source.leftMargin;
-            this.initialRightMargin = source.rightMargin;
-
-            setLayoutDirection(source.layoutDirection);
+            this.mMarginFlags = source.mMarginFlags;
         }
 
         /**
@@ -5935,6 +6049,12 @@
          */
         public MarginLayoutParams(LayoutParams source) {
             super(source);
+
+            mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+            mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
+
+            mMarginFlags &= ~NEED_RESOLUTION_MASK;
+            mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
         }
 
         /**
@@ -5957,8 +6077,13 @@
             topMargin = top;
             rightMargin = right;
             bottomMargin = bottom;
-            initialLeftMargin = left;
-            initialRightMargin = right;
+            mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
+            mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
+            if (isMarginRelative()) {
+                mMarginFlags |= NEED_RESOLUTION_MASK;
+            } else {
+                mMarginFlags &= ~NEED_RESOLUTION_MASK;
+            }
         }
 
         /**
@@ -5984,8 +6109,7 @@
             topMargin = top;
             endMargin = end;
             bottomMargin = bottom;
-            initialLeftMargin = 0;
-            initialRightMargin = 0;
+            mMarginFlags |= NEED_RESOLUTION_MASK;
         }
 
         /**
@@ -5997,6 +6121,7 @@
          */
         public void setMarginStart(int start) {
             startMargin = start;
+            mMarginFlags |= NEED_RESOLUTION_MASK;
         }
 
         /**
@@ -6007,8 +6132,11 @@
          * @return the start margin in pixels.
          */
         public int getMarginStart() {
-            if (startMargin != DEFAULT_RELATIVE) return startMargin;
-            switch(layoutDirection) {
+            if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
+            if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
+                doResolveMargins();
+            }
+            switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
                 case View.LAYOUT_DIRECTION_RTL:
                     return rightMargin;
                 case View.LAYOUT_DIRECTION_LTR:
@@ -6026,6 +6154,7 @@
          */
         public void setMarginEnd(int end) {
             endMargin = end;
+            mMarginFlags |= NEED_RESOLUTION_MASK;
         }
 
         /**
@@ -6036,8 +6165,11 @@
          * @return the end margin in pixels.
          */
         public int getMarginEnd() {
-            if (endMargin != DEFAULT_RELATIVE) return endMargin;
-            switch(layoutDirection) {
+            if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
+            if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
+                doResolveMargins();
+            }
+            switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
                 case View.LAYOUT_DIRECTION_RTL:
                     return leftMargin;
                 case View.LAYOUT_DIRECTION_LTR:
@@ -6055,7 +6187,7 @@
          * @return true if either marginStart or marginEnd has been set.
          */
         public boolean isMarginRelative() {
-            return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE);
+            return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
         }
 
         /**
@@ -6067,7 +6199,15 @@
         public void setLayoutDirection(int layoutDirection) {
             if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
                     layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
-            this.layoutDirection = layoutDirection;
+            if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
+                mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
+                mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
+                if (isMarginRelative()) {
+                    mMarginFlags |= NEED_RESOLUTION_MASK;
+                } else {
+                    mMarginFlags &= ~NEED_RESOLUTION_MASK;
+                }
+            }
         }
 
         /**
@@ -6077,7 +6217,7 @@
          * @return the layout direction.
          */
         public int getLayoutDirection() {
-            return layoutDirection;
+            return (mMarginFlags & LAYOUT_DIRECTION_MASK);
         }
 
         /**
@@ -6088,26 +6228,55 @@
         public void resolveLayoutDirection(int layoutDirection) {
             setLayoutDirection(layoutDirection);
 
-            if (!isMarginRelative()) return;
+            // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
+            // Will use the left and right margins if no relative margin is defined.
+            if (!isMarginRelative() ||
+                    (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
 
-            switch(layoutDirection) {
-                case View.LAYOUT_DIRECTION_RTL:
-                    leftMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialLeftMargin;
-                    rightMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialRightMargin;
-                    break;
-                case View.LAYOUT_DIRECTION_LTR:
-                default:
-                    leftMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialLeftMargin;
-                    rightMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialRightMargin;
-                    break;
+            // Proceed with resolution
+            doResolveMargins();
+        }
+
+        private void doResolveMargins() {
+            if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
+                // if left or right margins are not defined and if we have some start or end margin
+                // defined then use those start and end margins.
+                if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
+                        && startMargin > DEFAULT_MARGIN_RELATIVE) {
+                    leftMargin = startMargin;
+                }
+                if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
+                        && endMargin > DEFAULT_MARGIN_RELATIVE) {
+                    rightMargin = endMargin;
+                }
+            } else {
+                // We have some relative margins (either the start one or the end one or both). So use
+                // them and override what has been defined for left and right margins. If either start
+                // or end margin is not defined, just set it to default "0".
+                switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
+                    case View.LAYOUT_DIRECTION_RTL:
+                        leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                endMargin : DEFAULT_MARGIN_RESOLVED;
+                        rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                startMargin : DEFAULT_MARGIN_RESOLVED;
+                        break;
+                    case View.LAYOUT_DIRECTION_LTR:
+                    default:
+                        leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                startMargin : DEFAULT_MARGIN_RESOLVED;
+                        rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
+                                endMargin : DEFAULT_MARGIN_RESOLVED;
+                        break;
+                }
             }
+            mMarginFlags &= ~NEED_RESOLUTION_MASK;
         }
 
         /**
          * @hide
          */
         public boolean isLayoutRtl() {
-            return (layoutDirection == View.LAYOUT_DIRECTION_RTL);
+            return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
         }
 
         /**
diff --git a/core/java/android/view/ViewGroupOverlay.java b/core/java/android/view/ViewGroupOverlay.java
new file mode 100644
index 0000000..c1b24f2
--- /dev/null
+++ b/core/java/android/view/ViewGroupOverlay.java
@@ -0,0 +1,75 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+/**
+ * A group overlay is an extra layer that sits on top of a ViewGroup
+ * (the "host view") which is drawn after all other content in that view
+ * (including the view group's children). Interaction with the overlay
+ * layer is done by adding and removing views and drawables.
+ *
+ * <p>ViewGroupOverlay is a subclass of {@link ViewOverlay}, adding the ability to
+ * manage views for overlays on ViewGroups, in addition to the drawable
+ * support in ViewOverlay.</p>
+ *
+ * @see ViewGroup#getOverlay()
+ */
+public class ViewGroupOverlay extends ViewOverlay {
+
+    ViewGroupOverlay(Context context, View hostView) {
+        super(context, hostView);
+    }
+
+    /**
+     * Adds a View to the overlay. The bounds of the added view should be
+     * relative to the host view. Any view added to the overlay should be
+     * removed when it is no longer needed or no longer visible.
+     *
+     * <p>Views in the overlay are visual-only; they do not receive input
+     * events and do not participate in focus traversal. Overlay views
+     * are intended to be transient, such as might be needed by a temporary
+     * 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
+     * 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
+     * host view, then the view will be offset by (100, 200).</p>
+     *
+     * @param view The View to be added to the overlay. The added view will be
+     * drawn when the overlay is drawn.
+     * @see #remove(View)
+     * @see ViewOverlay#add(Drawable)
+     */
+    public void add(View view) {
+        mOverlayViewGroup.add(view);
+    }
+
+    /**
+     * Removes the specified View from the overlay.
+     *
+     * @param view The View to be removed from the overlay.
+     * @see #add(View)
+     * @see ViewOverlay#remove(Drawable)
+     */
+    public void remove(View view) {
+        mOverlayViewGroup.remove(view);
+    }
+}
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
new file mode 100644
index 0000000..78e2597
--- /dev/null
+++ b/core/java/android/view/ViewOverlay.java
@@ -0,0 +1,308 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+import java.util.ArrayList;
+
+/**
+ * An overlay is an extra layer that sits on top of a View (the "host view")
+ * which is drawn after all other content in that view (including children,
+ * if the view is a ViewGroup). Interaction with the overlay layer is done
+ * by adding and removing drawables.
+ *
+ * <p>An overlay requested from a ViewGroup is of type {@link ViewGroupOverlay},
+ * which also supports adding and removing views.</p>
+ *
+ * @see View#getOverlay() View.getOverlay()
+ * @see ViewGroup#getOverlay() ViewGroup.getOverlay()
+ * @see ViewGroupOverlay
+ */
+public class ViewOverlay {
+
+    /**
+     * The actual container for the drawables (and views, if it's a ViewGroupOverlay).
+     * All of the management and rendering details for the overlay are handled in
+     * OverlayViewGroup.
+     */
+    OverlayViewGroup mOverlayViewGroup;
+
+    ViewOverlay(Context context, View hostView) {
+        mOverlayViewGroup = new OverlayViewGroup(context, hostView);
+    }
+
+    /**
+     * Used internally by View and ViewGroup to handle drawing and invalidation
+     * of the overlay
+     * @return
+     */
+    ViewGroup getOverlayView() {
+        return mOverlayViewGroup;
+    }
+
+    /**
+     * Adds a Drawable to the overlay. The bounds of the drawable should be relative to
+     * the host view. Any drawable added to the overlay should be removed when it is no longer
+     * needed or no longer visible.
+     *
+     * @param drawable The Drawable to be added to the overlay. This drawable will be
+     * drawn when the view redraws its overlay.
+     * @see #remove(Drawable)
+     */
+    public void add(Drawable drawable) {
+        mOverlayViewGroup.add(drawable);
+    }
+
+    /**
+     * Removes the specified Drawable from the overlay.
+     *
+     * @param drawable The Drawable to be removed from the overlay.
+     * @see #add(Drawable)
+     */
+    public void remove(Drawable drawable) {
+        mOverlayViewGroup.remove(drawable);
+    }
+
+    /**
+     * Removes all content from the overlay.
+     */
+    public void clear() {
+        mOverlayViewGroup.clear();
+    }
+
+    boolean isEmpty() {
+        return mOverlayViewGroup.isEmpty();
+    }
+
+    /**
+     * OverlayViewGroup is a container that View and ViewGroup use to host
+     * drawables and views added to their overlays  ({@link ViewOverlay} and
+     * {@link ViewGroupOverlay}, respectively). Drawables are added to the overlay
+     * via the add/remove methods in ViewOverlay, Views are added/removed via
+     * ViewGroupOverlay. These drawable and view objects are
+     * drawn whenever the view itself is drawn; first the view draws its own
+     * content (and children, if it is a ViewGroup), then it draws its overlay
+     * (if it has one).
+     *
+     * <p>Besides managing and drawing the list of drawables, this class serves
+     * two purposes:
+     * (1) it noops layout calls because children are absolutely positioned and
+     * (2) it forwards all invalidation calls to its host view. The invalidation
+     * redirect is necessary because the overlay is not a child of the host view
+     * and invalidation cannot therefore follow the normal path up through the
+     * parent hierarchy.</p>
+     *
+     * @see View#getOverlay()
+     * @see ViewGroup#getOverlay()
+     */
+    static class OverlayViewGroup extends ViewGroup {
+
+        /**
+         * The View for which this is an overlay. Invalidations of the overlay are redirected to
+         * this host view.
+         */
+        View mHostView;
+
+        /**
+         * The set of drawables to draw when the overlay is rendered.
+         */
+        ArrayList<Drawable> mDrawables = null;
+
+        OverlayViewGroup(Context context, View hostView) {
+            super(context);
+            mHostView = hostView;
+            mAttachInfo = mHostView.mAttachInfo;
+            mRight = hostView.getWidth();
+            mBottom = hostView.getHeight();
+        }
+
+        public void add(Drawable drawable) {
+            if (mDrawables == null) {
+
+                mDrawables = new ArrayList<Drawable>();
+            }
+            if (!mDrawables.contains(drawable)) {
+                // Make each drawable unique in the overlay; can't add it more than once
+                mDrawables.add(drawable);
+                invalidate(drawable.getBounds());
+                drawable.setCallback(this);
+            }
+        }
+
+        public void remove(Drawable drawable) {
+            if (mDrawables != null) {
+                mDrawables.remove(drawable);
+                invalidate(drawable.getBounds());
+                drawable.setCallback(null);
+            }
+        }
+
+        public void add(View child) {
+            if (child.getParent() instanceof ViewGroup) {
+                ViewGroup parent = (ViewGroup) child.getParent();
+                if (parent != mHostView) {
+                    // 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];
+                    int[] hostViewLocation = new int[2];
+                    parent.getLocationOnScreen(parentLocation);
+                    mHostView.getLocationOnScreen(hostViewLocation);
+                    child.offsetLeftAndRight(parentLocation[0] - hostViewLocation[0]);
+                    child.offsetTopAndBottom(parentLocation[1] - hostViewLocation[1]);
+                }
+                parent.removeView(child);
+            }
+            super.addView(child);
+        }
+
+        public void remove(View view) {
+            super.removeView(view);
+        }
+
+        public void clear() {
+            removeAllViews();
+            mDrawables.clear();
+        }
+
+        boolean isEmpty() {
+            if (getChildCount() == 0 &&
+                    (mDrawables == null || mDrawables.size() == 0)) {
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void invalidateDrawable(Drawable drawable) {
+            invalidate(drawable.getBounds());
+        }
+
+        @Override
+        protected void dispatchDraw(Canvas canvas) {
+            super.dispatchDraw(canvas);
+            final int numDrawables = (mDrawables == null) ? 0 : mDrawables.size();
+            for (int i = 0; i < numDrawables; ++i) {
+                mDrawables.get(i).draw(canvas);
+            }
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            // Noop: children are positioned absolutely
+        }
+
+        /*
+         The following invalidation overrides exist for the purpose of redirecting invalidation to
+         the host view. The overlay is not parented to the host view (since a View cannot be a
+         parent), so the invalidation cannot proceed through the normal parent hierarchy.
+         There is a built-in assumption that the overlay exactly covers the host view, therefore
+         the invalidation rectangles received do not need to be adjusted when forwarded to
+         the host view.
+         */
+
+        @Override
+        public void invalidate(Rect dirty) {
+            super.invalidate(dirty);
+            if (mHostView != null) {
+                mHostView.invalidate(dirty);
+            }
+        }
+
+        @Override
+        public void invalidate(int l, int t, int r, int b) {
+            super.invalidate(l, t, r, b);
+            if (mHostView != null) {
+                mHostView.invalidate(l, t, r, b);
+            }
+        }
+
+        @Override
+        public void invalidate() {
+            super.invalidate();
+            if (mHostView != null) {
+                mHostView.invalidate();
+            }
+        }
+
+        @Override
+        void invalidate(boolean invalidateCache) {
+            super.invalidate(invalidateCache);
+            if (mHostView != null) {
+                mHostView.invalidate(invalidateCache);
+            }
+        }
+
+        @Override
+        void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
+            super.invalidateViewProperty(invalidateParent, forceRedraw);
+            if (mHostView != null) {
+                mHostView.invalidateViewProperty(invalidateParent, forceRedraw);
+            }
+        }
+
+        @Override
+        protected void invalidateParentCaches() {
+            super.invalidateParentCaches();
+            if (mHostView != null) {
+                mHostView.invalidateParentCaches();
+            }
+        }
+
+        @Override
+        protected void invalidateParentIfNeeded() {
+            super.invalidateParentIfNeeded();
+            if (mHostView != null) {
+                mHostView.invalidateParentIfNeeded();
+            }
+        }
+
+        public void invalidateChildFast(View child, final Rect dirty) {
+            if (mHostView != null) {
+                // Note: This is not a "fast" invalidation. Would be nice to instead invalidate
+                // using DisplayList properties and a dirty rect instead of causing a real
+                // invalidation of the host view
+                int left = child.mLeft;
+                int top = child.mTop;
+                if (!child.getMatrix().isIdentity()) {
+                    child.transformRect(dirty);
+                }
+                dirty.offset(left, top);
+                mHostView.invalidate(dirty);
+            }
+        }
+
+        @Override
+        public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
+            if (mHostView != null) {
+                dirty.offset(location[0], location[1]);
+                if (mHostView instanceof ViewGroup) {
+                    location[0] = 0;
+                    location[1] = 0;
+                    super.invalidateChildInParent(location, dirty);
+                    return ((ViewGroup) mHostView).invalidateChildInParent(location, dirty);
+                } else {
+                    invalidate(dirty);
+                }
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b8fae865..98b7877 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -42,7 +42,6 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
-import android.os.LatencyTimer;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
@@ -107,6 +106,7 @@
     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
+    private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
 
     private static final boolean USE_RENDER_THREAD = false;
 
@@ -115,9 +115,6 @@
      * at 60 Hz. This can be used to measure the potential framerate.
      */
     private static final String PROPERTY_PROFILE_RENDERING = "viewancestor.profile_rendering";
-    
-    private static final boolean MEASURE_LATENCY = false;
-    private static LatencyTimer lt;
 
     /**
      * Maximum time we allow the user to roll the trackball enough to generate
@@ -137,26 +134,15 @@
     private static boolean sRenderThreadQueried = false;
     private static final Object[] sRenderThreadQueryLock = new Object[0];
 
+    final Context mContext;
     final IWindowSession mWindowSession;
     final Display mDisplay;
     final String mBasePackageName;
 
-    long mLastTrackballTime = 0;
-    final TrackballAxis mTrackballAxisX = new TrackballAxis();
-    final TrackballAxis mTrackballAxisY = new TrackballAxis();
-
-    final SimulatedDpad mSimulatedDpad;
-
-    int mLastJoystickXDirection;
-    int mLastJoystickYDirection;
-    int mLastJoystickXKeyCode;
-    int mLastJoystickYKeyCode;
-
     final int[] mTmpLocation = new int[2];
 
     final TypedValue mTmpValue = new TypedValue();
-    
-    final InputMethodCallback mInputMethodCallback;
+
     final Thread mThread;
 
     final WindowLeaked mLocation;
@@ -196,7 +182,6 @@
     int mHeight;
     Rect mDirty;
     final Rect mCurrentDirty = new Rect();
-    final Rect mPreviousDirty = new Rect();
     boolean mIsAnimating;
 
     CompatibilityInfo.Translator mTranslator;
@@ -231,22 +216,23 @@
     int mClientWindowLayoutFlags;
     boolean mLastOverscanRequested;
 
-    /** @hide */
-    public static final int EVENT_NOT_HANDLED = 0;
-    /** @hide */
-    public static final int EVENT_HANDLED = 1;
-    /** @hide */
-    public static final int EVENT_IN_PROGRESS = 2;
-
     // Pool of queued input events.
     private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
     private QueuedInputEvent mQueuedInputEventPool;
     private int mQueuedInputEventPoolSize;
 
-    // Input event queue.
-    QueuedInputEvent mFirstPendingInputEvent;
-    QueuedInputEvent mCurrentInputEvent;
+    /* Input event queue.
+     * Pending input events are input events waiting to be delivered to the input stages
+     * and handled by the application.
+     */
+    QueuedInputEvent mPendingInputEventHead;
+    QueuedInputEvent mPendingInputEventTail;
+    int mPendingInputEventCount;
     boolean mProcessInputEventsScheduled;
+    String mPendingInputEventQueueLengthCounterName = "pq";
+
+    InputStage mFirstInputStage;
+    InputStage mFirstPostImeInputStage;
 
     boolean mWindowAttributesChanged = false;
     int mWindowAttributesChangesFlag = 0;
@@ -345,18 +331,8 @@
     }
     
     public ViewRootImpl(Context context, Display display) {
-        super();
-
-        if (MEASURE_LATENCY) {
-            if (lt == null) {
-                lt = new LatencyTimer(100, 1000);
-            }
-        }
-
-        // Initialize the statics when this class is first instantiated. This is
-        // done here instead of in the static block because Zygote does not
-        // allow the spawning of threads.
-        mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
+        mContext = context;
+        mWindowSession = WindowManagerGlobal.getWindowSession();
         mDisplay = display;
         mBasePackageName = context.getBasePackageName();
 
@@ -374,7 +350,6 @@
         mWinFrame = new Rect();
         mWindow = new W(this);
         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
-        mInputMethodCallback = new InputMethodCallback(this);
         mViewVisibility = View.GONE;
         mTransparentRegion = new Region();
         mPreviousTransparentRegion = new Region();
@@ -395,7 +370,6 @@
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mAttachInfo.mScreenOn = powerManager.isScreenOn();
         loadSystemProperties();
-        mSimulatedDpad = new SimulatedDpad(context);
     }
 
     /**
@@ -642,6 +616,23 @@
                 if (view.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
                     view.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
                 }
+
+                // Set up the input pipeline.
+                CharSequence counterSuffix = attrs.getTitle();
+                InputStage syntheticStage = new SyntheticInputStage();
+                InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticStage);
+                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
+                        "aq:native-post-ime:" + counterSuffix);
+                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
+                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
+                        "aq:ime:" + counterSuffix);
+                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
+                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
+                        "aq:native-pre-ime:" + counterSuffix);
+
+                mFirstInputStage = nativePreImeStage;
+                mFirstPostImeInputStage = earlyPostImeStage;
+                mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
             }
         }
     }
@@ -747,10 +738,11 @@
 
                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
-                mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
-                mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
-                        = mAttachInfo.mHardwareRenderer != null;
-
+                if (mAttachInfo.mHardwareRenderer != null) {
+                    mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
+                    mAttachInfo.mHardwareAccelerated =
+                            mAttachInfo.mHardwareAccelerationRequested = true;
+                }
             } else if (fakeHwAccelerated) {
                 // The window had wanted to use hardware acceleration, but this
                 // is not allowed in its process.  By setting this flag, it can
@@ -1213,6 +1205,7 @@
                 host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
             }
             host.dispatchAttachedToWindow(attachInfo, 0);
+            attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
             host.fitSystemWindows(mFitSystemWindowsInsets);
             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
@@ -1404,6 +1397,8 @@
 
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
+                mWindowsAnimating |=
+                        (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0;
 
                 if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
                         + " overscan=" + mPendingOverscanInsets.toShortString()
@@ -1947,20 +1942,16 @@
             // Would not normally trigger another layout, so just let it pass through as usual
             return true;
         }
+        if (!mLayoutRequesters.contains(view)) {
+            mLayoutRequesters.add(view);
+        }
         if (!mHandlingLayoutInLayoutRequest) {
-            if (!mLayoutRequesters.contains(view)) {
-                mLayoutRequesters.add(view);
-            }
+            // Let the request proceed normally; it will be processed in a second layout pass
+            // if necessary
             return true;
         } else {
-            Log.w("View", "requestLayout() called by " + view + " during second layout pass: " +
-                    "posting to next frame");
-            view.post(new Runnable() {
-                @Override
-                public void run() {
-                    view.requestLayout();
-                }
-            });
+            // Don't let the request proceed during the second layout pass.
+            // It will post to the next frame instead.
             return false;
         }
     }
@@ -1988,59 +1979,50 @@
                 // If no layout-request flags are set on the requesting views, there is no problem.
                 // If some requests are still pending, then we need to clear those flags and do
                 // a full request/measure/layout pass to handle this situation.
-
-                // Check state of layout flags for all requesters
-                ArrayList<View> mValidLayoutRequesters = null;
-                for (int i = 0; i < numViewsRequestingLayout; ++i) {
-                    View view = mLayoutRequesters.get(i);
-                    if ((view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) == View.PFLAG_FORCE_LAYOUT) {
-                        while (view != null && view.mAttachInfo != null && view.mParent != null &&
-                                (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
-                            if ((view.mViewFlags & View.VISIBILITY_MASK) != View.GONE) {
-                                // Only trigger new requests for non-GONE views
-                                Log.w(TAG, "requestLayout() improperly called during " +
-                                        "layout: running second layout pass for " + view);
-                                if (mValidLayoutRequesters == null) {
-                                    mValidLayoutRequesters = new ArrayList<View>();
-                                }
-                                mValidLayoutRequesters.add(view);
-                                break;
-                            }
-                            if (view.mParent instanceof View) {
-                                view = (View) view.mParent;
-                            } else {
-                                view = null;
-                            }
-                        }
-                    }
-                }
-                if (mValidLayoutRequesters != null) {
-                    // Clear flags throughout hierarchy, walking up from each flagged requester
-                    for (int i = 0; i < numViewsRequestingLayout; ++i) {
-                        View view = mLayoutRequesters.get(i);
-                        while (view != null &&
-                                (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
-                            view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
-                            if (view.mParent instanceof View) {
-                                view = (View) view.mParent;
-                            } else {
-                                view = null;
-                            }
-                        }
-                    }
-                    // Process fresh layout requests, then measure and layout
+                ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
+                        false);
+                if (validLayoutRequesters != null) {
+                    // Set this flag to indicate that any further requests are happening during
+                    // the second pass, which may result in posting those requests to the next
+                    // frame instead
                     mHandlingLayoutInLayoutRequest = true;
-                    int numValidRequests = mValidLayoutRequesters.size();
+
+                    // Process fresh layout requests, then measure and layout
+                    int numValidRequests = validLayoutRequesters.size();
                     for (int i = 0; i < numValidRequests; ++i) {
-                        mValidLayoutRequesters.get(i).requestLayout();
+                        final View view = validLayoutRequesters.get(i);
+                        Log.w("View", "requestLayout() improperly called by " + view +
+                                " during layout: running second layout pass");
+                        view.requestLayout();
                     }
                     measureHierarchy(host, lp, mView.getContext().getResources(),
                             desiredWindowWidth, desiredWindowHeight);
                     mInLayout = true;
                     host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
+
                     mHandlingLayoutInLayoutRequest = false;
+
+                    // Check the valid requests again, this time without checking/clearing the
+                    // layout flags, since requests happening during the second pass get noop'd
+                    validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);
+                    if (validLayoutRequesters != null) {
+                        final ArrayList<View> finalRequesters = validLayoutRequesters;
+                        // Post second-pass requests to the next frame
+                        getRunQueue().post(new Runnable() {
+                            @Override
+                            public void run() {
+                                int numValidRequests = finalRequesters.size();
+                                for (int i = 0; i < numValidRequests; ++i) {
+                                    final View view = finalRequesters.get(i);
+                                    Log.w("View", "requestLayout() improperly called by " + view +
+                                            " during second layout pass: posting in next frame");
+                                    view.requestLayout();
+                                }
+                            }
+                        });
+                    }
                 }
-                mLayoutRequesters.clear();
+
             }
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -2048,6 +2030,68 @@
         mInLayout = false;
     }
 
+    /**
+     * This method is called during layout when there have been calls to requestLayout() during
+     * layout. It walks through the list of views that requested layout to determine which ones
+     * still need it, based on visibility in the hierarchy and whether they have already been
+     * handled (as is usually the case with ListView children).
+     *
+     * @param layoutRequesters The list of views that requested layout during layout
+     * @param secondLayoutRequests Whether the requests were issued during the second layout pass.
+     * If so, the FORCE_LAYOUT flag was not set on requesters.
+     * @return A list of the actual views that still need to be laid out.
+     */
+    private ArrayList<View> getValidLayoutRequesters(ArrayList<View> layoutRequesters,
+            boolean secondLayoutRequests) {
+
+        int numViewsRequestingLayout = layoutRequesters.size();
+        ArrayList<View> validLayoutRequesters = null;
+        for (int i = 0; i < numViewsRequestingLayout; ++i) {
+            View view = layoutRequesters.get(i);
+            if (view != null && view.mAttachInfo != null && view.mParent != null &&
+                    (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) ==
+                            View.PFLAG_FORCE_LAYOUT)) {
+                boolean gone = false;
+                View parent = view;
+                // Only trigger new requests for views in a non-GONE hierarchy
+                while (parent != null) {
+                    if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) {
+                        gone = true;
+                        break;
+                    }
+                    if (parent.mParent instanceof View) {
+                        parent = (View) parent.mParent;
+                    } else {
+                        parent = null;
+                    }
+                }
+                if (!gone) {
+                    if (validLayoutRequesters == null) {
+                        validLayoutRequesters = new ArrayList<View>();
+                    }
+                    validLayoutRequesters.add(view);
+                }
+            }
+        }
+        if (!secondLayoutRequests) {
+            // If we're checking the layout flags, then we need to clean them up also
+            for (int i = 0; i < numViewsRequestingLayout; ++i) {
+                View view = layoutRequesters.get(i);
+                while (view != null &&
+                        (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0) {
+                    view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
+                    if (view.mParent instanceof View) {
+                        view = (View) view.mParent;
+                    } else {
+                        view = null;
+                    }
+                }
+            }
+        }
+        layoutRequesters.clear();
+        return validLayoutRequesters;
+    }
+
     public void requestTransparentRegion(View child) {
         // the test below should not fail unless someone is messing with us
         checkThread();
@@ -2315,14 +2359,10 @@
                 mResizeAlpha = resizeAlpha;
 
                 mCurrentDirty.set(dirty);
-                mCurrentDirty.union(mPreviousDirty);
-                mPreviousDirty.set(dirty);
                 dirty.setEmpty();
 
-                if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
-                        animating ? null : mCurrentDirty)) {
-                    mPreviousDirty.set(0, 0, mWidth, mHeight);
-                }
+                attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
+                        animating ? null : mCurrentDirty);
             } else {
                 // If we get here with a disabled & requested hardware renderer, something went
                 // wrong (an invalidate posted right before we destroyed the hardware surface
@@ -2377,6 +2417,8 @@
 
             canvas = mSurface.lockCanvas(dirty);
 
+            // The dirty rectangle can be modified by Surface.lockCanvas()
+            //noinspection ConstantConditions
             if (left != dirty.left || top != dirty.top || right != dirty.right ||
                     bottom != dirty.bottom) {
                 attachInfo.mIgnoreDirtyState = true;
@@ -2758,6 +2800,7 @@
                     mAttachInfo.mHardwareRenderer.isEnabled()) {
                 mAttachInfo.mHardwareRenderer.validate();
             }
+            mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
             mView.dispatchDetachedFromWindow();
         }
 
@@ -2788,7 +2831,7 @@
             mWindowSession.remove(mWindow);
         } catch (RemoteException e) {
         }
-        
+
         // Dispose the input channel after removing the window so the Window Manager
         // doesn't interpret the input channel being closed as an abnormal termination.
         if (mInputChannel != null) {
@@ -2866,7 +2909,6 @@
     private final static int MSG_DISPATCH_KEY = 7;
     private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
     private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
-    private final static int MSG_IME_FINISHED_EVENT = 10;
     private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
     private final static int MSG_FINISH_INPUT_CONNECTION = 12;
     private final static int MSG_CHECK_FOCUS = 13;
@@ -2904,8 +2946,6 @@
                     return "MSG_DISPATCH_APP_VISIBILITY";
                 case MSG_DISPATCH_GET_NEW_SURFACE:
                     return "MSG_DISPATCH_GET_NEW_SURFACE";
-                case MSG_IME_FINISHED_EVENT:
-                    return "MSG_IME_FINISHED_EVENT";
                 case MSG_DISPATCH_KEY_FROM_IME:
                     return "MSG_DISPATCH_KEY_FROM_IME";
                 case MSG_FINISH_INPUT_CONNECTION:
@@ -2947,9 +2987,6 @@
                 info.target.invalidate(info.left, info.top, info.right, info.bottom);
                 info.recycle();
                 break;
-            case MSG_IME_FINISHED_EVENT:
-                handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
-                break;
             case MSG_PROCESS_INPUT_EVENTS:
                 mProcessInputEventsScheduled = false;
                 doProcessInputEvents();
@@ -3026,8 +3063,7 @@
                         boolean inTouchMode = msg.arg2 != 0;
                         ensureTouchModeLocally(inTouchMode);
 
-                        if (mAttachInfo.mHardwareRenderer != null &&
-                                mSurface != null && mSurface.isValid()) {
+                        if (mAttachInfo.mHardwareRenderer != null && mSurface.isValid()){
                             mFullRedrawNeeded = true;
                             try {
                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
@@ -3058,6 +3094,7 @@
                         }
                         mAttachInfo.mKeyDispatchState.reset();
                         mView.dispatchWindowFocusChanged(hasWindowFocus);
+                        mAttachInfo.mTreeObserver.dispatchOnWindowFocusChange(hasWindowFocus);
                     }
 
                     // Note: must be done after the focus change callbacks,
@@ -3279,385 +3316,1425 @@
         return false;
     }
 
-    private int deliverInputEvent(QueuedInputEvent q) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
-        try {
+    /**
+     * Base class for implementing a stage in the chain of responsibility
+     * for processing input events.
+     * <p>
+     * Events are delivered to the stage by the {@link #deliver} method.  The stage
+     * then has the choice of finishing the event or forwarding it to the next stage.
+     * </p>
+     */
+    abstract class InputStage {
+        private final InputStage mNext;
+
+        protected static final int FORWARD = 0;
+        protected static final int FINISH_HANDLED = 1;
+        protected static final int FINISH_NOT_HANDLED = 2;
+
+        /**
+         * Creates an input stage.
+         * @param next The next stage to which events should be forwarded.
+         */
+        public InputStage(InputStage next) {
+            mNext = next;
+        }
+
+        /**
+         * Delivers an event to be processed.
+         */
+        public final void deliver(QueuedInputEvent q) {
+            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
+                forward(q);
+            } else if (mView == null || !mAdded) {
+                finish(q, false);
+            } else {
+                apply(q, onProcess(q));
+            }
+        }
+
+        /**
+         * Marks the the input event as finished then forwards it to the next stage.
+         */
+        protected void finish(QueuedInputEvent q, boolean handled) {
+            q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
+            if (handled) {
+                q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
+            }
+            forward(q);
+        }
+
+        /**
+         * Forwards the event to the next stage.
+         */
+        protected void forward(QueuedInputEvent q) {
+            onDeliverToNext(q);
+        }
+
+        /**
+         * Applies a result code from {@link #onProcess} to the specified event.
+         */
+        protected void apply(QueuedInputEvent q, int result) {
+            if (result == FORWARD) {
+                forward(q);
+            } else if (result == FINISH_HANDLED) {
+                finish(q, true);
+            } else if (result == FINISH_NOT_HANDLED) {
+                finish(q, false);
+            } else {
+                throw new IllegalArgumentException("Invalid result: " + result);
+            }
+        }
+
+        /**
+         * Called when an event is ready to be processed.
+         * @return A result code indicating how the event was handled.
+         */
+        protected int onProcess(QueuedInputEvent q) {
+            return FORWARD;
+        }
+
+        /**
+         * Called when an event is being delivered to the next stage.
+         */
+        protected void onDeliverToNext(QueuedInputEvent q) {
+            if (mNext != null) {
+                mNext.deliver(q);
+            } else {
+                finishInputEvent(q);
+            }
+        }
+    }
+
+    /**
+     * Base class for implementing an input pipeline stage that supports
+     * asynchronous and out-of-order processing of input events.
+     * <p>
+     * In addition to what a normal input stage can do, an asynchronous
+     * input stage may also defer an input event that has been delivered to it
+     * and finish or forward it later.
+     * </p>
+     */
+    abstract class AsyncInputStage extends InputStage {
+        private final String mTraceCounter;
+
+        private QueuedInputEvent mQueueHead;
+        private QueuedInputEvent mQueueTail;
+        private int mQueueLength;
+
+        protected static final int DEFER = 3;
+
+        /**
+         * Creates an asynchronous input stage.
+         * @param next The next stage to which events should be forwarded.
+         * @param traceCounter The name of a counter to record the size of
+         * the queue of pending events.
+         */
+        public AsyncInputStage(InputStage next, String traceCounter) {
+            super(next);
+            mTraceCounter = traceCounter;
+        }
+
+        /**
+         * Marks the event as deferred, which is to say that it will be handled
+         * asynchronously.  The caller is responsible for calling {@link #forward}
+         * or {@link #finish} later when it is done handling the event.
+         */
+        protected void defer(QueuedInputEvent q) {
+            q.mFlags |= QueuedInputEvent.FLAG_DEFERRED;
+            enqueue(q);
+        }
+
+        @Override
+        protected void forward(QueuedInputEvent q) {
+            // Clear the deferred flag.
+            q.mFlags &= ~QueuedInputEvent.FLAG_DEFERRED;
+
+            // Fast path if the queue is empty.
+            QueuedInputEvent curr = mQueueHead;
+            if (curr == null) {
+                super.forward(q);
+                return;
+            }
+
+            // Determine whether the event must be serialized behind any others
+            // before it can be delivered to the next stage.  This is done because
+            // deferred events might be handled out of order by the stage.
+            final int deviceId = q.mEvent.getDeviceId();
+            QueuedInputEvent prev = null;
+            boolean blocked = false;
+            while (curr != null && curr != q) {
+                if (!blocked && deviceId == curr.mEvent.getDeviceId()) {
+                    blocked = true;
+                }
+                prev = curr;
+                curr = curr.mNext;
+            }
+
+            // If the event is blocked, then leave it in the queue to be delivered later.
+            // Note that the event might not yet be in the queue if it was not previously
+            // deferred so we will enqueue it if needed.
+            if (blocked) {
+                if (curr == null) {
+                    enqueue(q);
+                }
+                return;
+            }
+
+            // The event is not blocked.  Deliver it immediately.
+            if (curr != null) {
+                curr = curr.mNext;
+                dequeue(q, prev);
+            }
+            super.forward(q);
+
+            // Dequeuing this event may have unblocked successors.  Deliver them.
+            while (curr != null) {
+                if (deviceId == curr.mEvent.getDeviceId()) {
+                    if ((curr.mFlags & QueuedInputEvent.FLAG_DEFERRED) != 0) {
+                        break;
+                    }
+                    QueuedInputEvent next = curr.mNext;
+                    dequeue(curr, prev);
+                    super.forward(curr);
+                    curr = next;
+                } else {
+                    prev = curr;
+                    curr = curr.mNext;
+                }
+            }
+        }
+
+        @Override
+        protected void apply(QueuedInputEvent q, int result) {
+            if (result == DEFER) {
+                defer(q);
+            } else {
+                super.apply(q, result);
+            }
+        }
+
+        private void enqueue(QueuedInputEvent q) {
+            if (mQueueTail == null) {
+                mQueueHead = q;
+                mQueueTail = q;
+            } else {
+                mQueueTail.mNext = q;
+                mQueueTail = q;
+            }
+
+            mQueueLength += 1;
+            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
+        }
+
+        private void dequeue(QueuedInputEvent q, QueuedInputEvent prev) {
+            if (prev == null) {
+                mQueueHead = q.mNext;
+            } else {
+                prev.mNext = q.mNext;
+            }
+            if (mQueueTail == q) {
+                mQueueTail = prev;
+            }
+            q.mNext = null;
+
+            mQueueLength -= 1;
+            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mTraceCounter, mQueueLength);
+        }
+    }
+
+    /**
+     * Delivers pre-ime input events to a native activity.
+     * Does not support pointer events.
+     */
+    final class NativePreImeInputStage extends AsyncInputStage {
+        public NativePreImeInputStage(InputStage next, String traceCounter) {
+            super(next, traceCounter);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
+            return FORWARD;
+        }
+    }
+
+    /**
+     * Delivers pre-ime input events to the view hierarchy.
+     * Does not support pointer events.
+     */
+    final class ViewPreImeInputStage extends InputStage {
+        public ViewPreImeInputStage(InputStage next) {
+            super(next);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
             if (q.mEvent instanceof KeyEvent) {
-                return deliverKeyEvent(q);
+                return processKeyEvent(q);
+            }
+            return FORWARD;
+        }
+
+        private int processKeyEvent(QueuedInputEvent q) {
+            final KeyEvent event = (KeyEvent)q.mEvent;
+            if (mView.dispatchKeyEventPreIme(event)) {
+                return FINISH_HANDLED;
+            }
+            return FORWARD;
+        }
+    }
+
+    /**
+     * Delivers input events to the ime.
+     * Does not support pointer events.
+     */
+    final class ImeInputStage extends AsyncInputStage
+            implements InputMethodManager.FinishedInputEventCallback {
+        public ImeInputStage(InputStage next, String traceCounter) {
+            super(next, traceCounter);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
+            if (mLastWasImTarget) {
+                InputMethodManager imm = InputMethodManager.peekInstance();
+                if (imm != null) {
+                    final InputEvent event = q.mEvent;
+                    if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
+                    int result = imm.dispatchInputEvent(event, q, this, mHandler);
+                    if (result == InputMethodManager.DISPATCH_HANDLED) {
+                        return FINISH_HANDLED;
+                    } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
+                        return FINISH_NOT_HANDLED;
+                    } else {
+                        return DEFER; // callback will be invoked later
+                    }
+                }
+            }
+            return FORWARD;
+        }
+
+        @Override
+        public void onFinishedInputEvent(Object token, boolean handled) {
+            QueuedInputEvent q = (QueuedInputEvent)token;
+            if (handled) {
+                finish(q, true);
+                return;
+            }
+
+            // If the window doesn't currently have input focus, then drop
+            // this event.  This could be an event that came back from the
+            // IME dispatch but the window has lost focus in the meantime.
+            if (!mAttachInfo.mHasWindowFocus && !isTerminalInputEvent(q.mEvent)) {
+                Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
+                finish(q, false);
+                return;
+            }
+
+            forward(q);
+        }
+    }
+
+    /**
+     * Performs early processing of post-ime input events.
+     */
+    final class EarlyPostImeInputStage extends InputStage {
+        public EarlyPostImeInputStage(InputStage next) {
+            super(next);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
+            if (q.mEvent instanceof KeyEvent) {
+                return processKeyEvent(q);
             } else {
                 final int source = q.mEvent.getSource();
                 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-                    return deliverPointerEvent(q);
-                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
-                    return deliverTrackballEvent(q);
-                } else {
-                    return deliverGenericMotionEvent(q);
+                    return processPointerEvent(q);
                 }
             }
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+            return FORWARD;
+        }
+
+        private int processKeyEvent(QueuedInputEvent q) {
+            final KeyEvent event = (KeyEvent)q.mEvent;
+
+            // If the key's purpose is to exit touch mode then we consume it
+            // and consider it handled.
+            if (checkForLeavingTouchModeAndConsume(event)) {
+                return FINISH_HANDLED;
+            }
+
+            // Make sure the fallback event policy sees all keys that will be
+            // delivered to the view hierarchy.
+            mFallbackEventHandler.preDispatchKeyEvent(event);
+            return FORWARD;
+        }
+
+        private int processPointerEvent(QueuedInputEvent q) {
+            final MotionEvent event = (MotionEvent)q.mEvent;
+
+            // Translate the pointer event for compatibility, if needed.
+            if (mTranslator != null) {
+                mTranslator.translateEventInScreenToAppWindow(event);
+            }
+
+            // Enter touch mode on down or scroll.
+            final int action = event.getAction();
+            if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
+                ensureTouchMode(true);
+            }
+
+            // Offset the scroll position.
+            if (mCurScrollY != 0) {
+                event.offsetLocation(0, mCurScrollY);
+            }
+
+            // Remember the touch position for possible drag-initiation.
+            if (event.isTouchEvent()) {
+                mLastTouchPoint.x = event.getRawX();
+                mLastTouchPoint.y = event.getRawY();
+            }
+            return FORWARD;
         }
     }
 
-    private int deliverInputEventPostIme(QueuedInputEvent q) {
-        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEventPostIme");
-        try {
+    /**
+     * Delivers post-ime input events to a native activity.
+     */
+    final class NativePostImeInputStage extends AsyncInputStage {
+        public NativePostImeInputStage(InputStage next, String traceCounter) {
+            super(next, traceCounter);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
+            return FORWARD;
+        }
+    }
+
+    /**
+     * Delivers post-ime input events to the view hierarchy.
+     */
+    final class ViewPostImeInputStage extends InputStage {
+        public ViewPostImeInputStage(InputStage next) {
+            super(next);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
             if (q.mEvent instanceof KeyEvent) {
-                return deliverKeyEventPostIme(q);
+                return processKeyEvent(q);
             } else {
                 final int source = q.mEvent.getSource();
-                if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
-                    return deliverTrackballEventPostIme(q);
+                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+                    return processPointerEvent(q);
+                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+                    return processTrackballEvent(q);
                 } else {
-                    return deliverGenericMotionEventPostIme(q);
+                    return processGenericMotionEvent(q);
                 }
             }
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+
+        private int processKeyEvent(QueuedInputEvent q) {
+            final KeyEvent event = (KeyEvent)q.mEvent;
+
+            // Deliver the key to the view hierarchy.
+            if (mView.dispatchKeyEvent(event)) {
+                return FINISH_HANDLED;
+            }
+
+            // If the Control modifier is held, try to interpret the key as a shortcut.
+            if (event.getAction() == KeyEvent.ACTION_DOWN
+                    && event.isCtrlPressed()
+                    && event.getRepeatCount() == 0
+                    && !KeyEvent.isModifierKey(event.getKeyCode())) {
+                if (mView.dispatchKeyShortcutEvent(event)) {
+                    return FINISH_HANDLED;
+                }
+            }
+
+            // Apply the fallback event policy.
+            if (mFallbackEventHandler.dispatchKeyEvent(event)) {
+                return FINISH_HANDLED;
+            }
+
+            // Handle automatic focus changes.
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                int direction = 0;
+                switch (event.getKeyCode()) {
+                    case KeyEvent.KEYCODE_DPAD_LEFT:
+                        if (event.hasNoModifiers()) {
+                            direction = View.FOCUS_LEFT;
+                        }
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_RIGHT:
+                        if (event.hasNoModifiers()) {
+                            direction = View.FOCUS_RIGHT;
+                        }
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_UP:
+                        if (event.hasNoModifiers()) {
+                            direction = View.FOCUS_UP;
+                        }
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_DOWN:
+                        if (event.hasNoModifiers()) {
+                            direction = View.FOCUS_DOWN;
+                        }
+                        break;
+                    case KeyEvent.KEYCODE_TAB:
+                        if (event.hasNoModifiers()) {
+                            direction = View.FOCUS_FORWARD;
+                        } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                            direction = View.FOCUS_BACKWARD;
+                        }
+                        break;
+                }
+                if (direction != 0) {
+                    View focused = mView.findFocus();
+                    if (focused != null) {
+                        View v = focused.focusSearch(direction);
+                        if (v != null && v != focused) {
+                            // do the math the get the interesting rect
+                            // of previous focused into the coord system of
+                            // newly focused view
+                            focused.getFocusedRect(mTempRect);
+                            if (mView instanceof ViewGroup) {
+                                ((ViewGroup) mView).offsetDescendantRectToMyCoords(
+                                        focused, mTempRect);
+                                ((ViewGroup) mView).offsetRectIntoDescendantCoords(
+                                        v, mTempRect);
+                            }
+                            if (v.requestFocus(direction, mTempRect)) {
+                                playSoundEffect(SoundEffectConstants
+                                        .getContantForFocusDirection(direction));
+                                return FINISH_HANDLED;
+                            }
+                        }
+
+                        // Give the focused view a last chance to handle the dpad key.
+                        if (mView.dispatchUnhandledMove(focused, direction)) {
+                            return FINISH_HANDLED;
+                        }
+                    } else {
+                        // find the best view to give focus to in this non-touch-mode with no-focus
+                        View v = focusSearch(null, direction);
+                        if (v != null && v.requestFocus(direction)) {
+                            return FINISH_HANDLED;
+                        }
+                    }
+                }
+            }
+            return FORWARD;
+        }
+
+        private int processPointerEvent(QueuedInputEvent q) {
+            final MotionEvent event = (MotionEvent)q.mEvent;
+
+            if (mView.dispatchPointerEvent(event)) {
+                return FINISH_HANDLED;
+            }
+            return FORWARD;
+        }
+
+        private int processTrackballEvent(QueuedInputEvent q) {
+            final MotionEvent event = (MotionEvent)q.mEvent;
+
+            if (mView.dispatchTrackballEvent(event)) {
+                return FINISH_HANDLED;
+            }
+            return FORWARD;
+        }
+
+        private int processGenericMotionEvent(QueuedInputEvent q) {
+            final MotionEvent event = (MotionEvent)q.mEvent;
+
+            // Deliver the event to the view.
+            if (mView.dispatchGenericMotionEvent(event)) {
+                return FINISH_HANDLED;
+            }
+            return FORWARD;
         }
     }
 
-    private int deliverPointerEvent(QueuedInputEvent q) {
-        final MotionEvent event = (MotionEvent)q.mEvent;
-        final boolean isTouchEvent = event.isTouchEvent();
-        if (mInputEventConsistencyVerifier != null) {
-            if (isTouchEvent) {
-                mInputEventConsistencyVerifier.onTouchEvent(event, 0);
+    /**
+     * Performs synthesis of new input events from unhandled input events.
+     */
+    final class SyntheticInputStage extends InputStage {
+        private final SyntheticTrackballHandler mTrackball = new SyntheticTrackballHandler();
+        private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
+        private final SyntheticTouchNavigationHandler mTouchNavigation =
+                new SyntheticTouchNavigationHandler();
+
+        public SyntheticInputStage() {
+            super(null);
+        }
+
+        @Override
+        protected int onProcess(QueuedInputEvent q) {
+            q.mFlags |= QueuedInputEvent.FLAG_RESYNTHESIZED;
+            if (q.mEvent instanceof MotionEvent) {
+                final MotionEvent event = (MotionEvent)q.mEvent;
+                final int source = event.getSource();
+                if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+                    mTrackball.process(event);
+                    return FINISH_HANDLED;
+                } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+                    mJoystick.process(event);
+                    return FINISH_HANDLED;
+                } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
+                        == InputDevice.SOURCE_TOUCH_NAVIGATION) {
+                    mTouchNavigation.process(event);
+                    return FINISH_HANDLED;
+                }
+            }
+            return FORWARD;
+        }
+
+        @Override
+        protected void onDeliverToNext(QueuedInputEvent q) {
+            if ((q.mFlags & QueuedInputEvent.FLAG_RESYNTHESIZED) == 0) {
+                // Cancel related synthetic events if any prior stage has handled the event.
+                if (q.mEvent instanceof MotionEvent) {
+                    final MotionEvent event = (MotionEvent)q.mEvent;
+                    final int source = event.getSource();
+                    if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+                        mTrackball.cancel(event);
+                    } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+                        mJoystick.cancel(event);
+                    } else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
+                            == InputDevice.SOURCE_TOUCH_NAVIGATION) {
+                        mTouchNavigation.cancel(event);
+                    }
+                }
+            }
+            super.onDeliverToNext(q);
+        }
+    }
+
+    /**
+     * Creates dpad events from unhandled trackball movements.
+     */
+    final class SyntheticTrackballHandler {
+        private final TrackballAxis mX = new TrackballAxis();
+        private final TrackballAxis mY = new TrackballAxis();
+        private long mLastTime;
+
+        public void process(MotionEvent event) {
+            // Translate the trackball event into DPAD keys and try to deliver those.
+            long curTime = SystemClock.uptimeMillis();
+            if ((mLastTime + MAX_TRACKBALL_DELAY) < curTime) {
+                // It has been too long since the last movement,
+                // so restart at the beginning.
+                mX.reset(0);
+                mY.reset(0);
+                mLastTime = curTime;
+            }
+
+            final int action = event.getAction();
+            final int metaState = event.getMetaState();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN:
+                    mX.reset(2);
+                    mY.reset(2);
+                    enqueueInputEvent(new KeyEvent(curTime, curTime,
+                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
+                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
+                            InputDevice.SOURCE_KEYBOARD));
+                    break;
+                case MotionEvent.ACTION_UP:
+                    mX.reset(2);
+                    mY.reset(2);
+                    enqueueInputEvent(new KeyEvent(curTime, curTime,
+                            KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
+                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
+                            InputDevice.SOURCE_KEYBOARD));
+                    break;
+            }
+
+            if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
+                    + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
+                    + " move=" + event.getX()
+                    + " / Y=" + mY.position + " step="
+                    + mY.step + " dir=" + mY.dir + " acc=" + mY.acceleration
+                    + " move=" + event.getY());
+            final float xOff = mX.collect(event.getX(), event.getEventTime(), "X");
+            final float yOff = mY.collect(event.getY(), event.getEventTime(), "Y");
+
+            // Generate DPAD events based on the trackball movement.
+            // We pick the axis that has moved the most as the direction of
+            // the DPAD.  When we generate DPAD events for one axis, then the
+            // other axis is reset -- we don't want to perform DPAD jumps due
+            // to slight movements in the trackball when making major movements
+            // along the other axis.
+            int keycode = 0;
+            int movement = 0;
+            float accel = 1;
+            if (xOff > yOff) {
+                movement = mX.generate();
+                if (movement != 0) {
+                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
+                            : KeyEvent.KEYCODE_DPAD_LEFT;
+                    accel = mX.acceleration;
+                    mY.reset(2);
+                }
+            } else if (yOff > 0) {
+                movement = mY.generate();
+                if (movement != 0) {
+                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
+                            : KeyEvent.KEYCODE_DPAD_UP;
+                    accel = mY.acceleration;
+                    mX.reset(2);
+                }
+            }
+
+            if (keycode != 0) {
+                if (movement < 0) movement = -movement;
+                int accelMovement = (int)(movement * accel);
+                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+                        + " accelMovement=" + accelMovement
+                        + " accel=" + accel);
+                if (accelMovement > movement) {
+                    if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
+                            + keycode);
+                    movement--;
+                    int repeatCount = accelMovement - movement;
+                    enqueueInputEvent(new KeyEvent(curTime, curTime,
+                            KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
+                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
+                            InputDevice.SOURCE_KEYBOARD));
+                }
+                while (movement > 0) {
+                    if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
+                            + keycode);
+                    movement--;
+                    curTime = SystemClock.uptimeMillis();
+                    enqueueInputEvent(new KeyEvent(curTime, curTime,
+                            KeyEvent.ACTION_DOWN, keycode, 0, metaState,
+                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
+                            InputDevice.SOURCE_KEYBOARD));
+                    enqueueInputEvent(new KeyEvent(curTime, curTime,
+                            KeyEvent.ACTION_UP, keycode, 0, metaState,
+                            KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
+                            InputDevice.SOURCE_KEYBOARD));
+                }
+                mLastTime = curTime;
+            }
+        }
+
+        public void cancel(MotionEvent event) {
+            mLastTime = Integer.MIN_VALUE;
+
+            // If we reach this, we consumed a trackball event.
+            // Because we will not translate the trackball event into a key event,
+            // touch mode will not exit, so we exit touch mode here.
+            if (mView != null && mAdded) {
+                ensureTouchMode(false);
+            }
+        }
+    }
+
+    /**
+     * Maintains state information for a single trackball axis, generating
+     * discrete (DPAD) movements based on raw trackball motion.
+     */
+    static final class TrackballAxis {
+        /**
+         * The maximum amount of acceleration we will apply.
+         */
+        static final float MAX_ACCELERATION = 20;
+
+        /**
+         * The maximum amount of time (in milliseconds) between events in order
+         * for us to consider the user to be doing fast trackball movements,
+         * and thus apply an acceleration.
+         */
+        static final long FAST_MOVE_TIME = 150;
+
+        /**
+         * Scaling factor to the time (in milliseconds) between events to how
+         * much to multiple/divide the current acceleration.  When movement
+         * is < FAST_MOVE_TIME this multiplies the acceleration; when >
+         * FAST_MOVE_TIME it divides it.
+         */
+        static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
+
+        static final float FIRST_MOVEMENT_THRESHOLD = 0.5f;
+        static final float SECOND_CUMULATIVE_MOVEMENT_THRESHOLD = 2.0f;
+        static final float SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD = 1.0f;
+
+        float position;
+        float acceleration = 1;
+        long lastMoveTime = 0;
+        int step;
+        int dir;
+        int nonAccelMovement;
+
+        void reset(int _step) {
+            position = 0;
+            acceleration = 1;
+            lastMoveTime = 0;
+            step = _step;
+            dir = 0;
+        }
+
+        /**
+         * Add trackball movement into the state.  If the direction of movement
+         * has been reversed, the state is reset before adding the
+         * movement (so that you don't have to compensate for any previously
+         * collected movement before see the result of the movement in the
+         * new direction).
+         *
+         * @return Returns the absolute value of the amount of movement
+         * collected so far.
+         */
+        float collect(float off, long time, String axis) {
+            long normTime;
+            if (off > 0) {
+                normTime = (long)(off * FAST_MOVE_TIME);
+                if (dir < 0) {
+                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
+                    position = 0;
+                    step = 0;
+                    acceleration = 1;
+                    lastMoveTime = 0;
+                }
+                dir = 1;
+            } else if (off < 0) {
+                normTime = (long)((-off) * FAST_MOVE_TIME);
+                if (dir > 0) {
+                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
+                    position = 0;
+                    step = 0;
+                    acceleration = 1;
+                    lastMoveTime = 0;
+                }
+                dir = -1;
             } else {
-                mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
+                normTime = 0;
+            }
+
+            // The number of milliseconds between each movement that is
+            // considered "normal" and will not result in any acceleration
+            // or deceleration, scaled by the offset we have here.
+            if (normTime > 0) {
+                long delta = time - lastMoveTime;
+                lastMoveTime = time;
+                float acc = acceleration;
+                if (delta < normTime) {
+                    // The user is scrolling rapidly, so increase acceleration.
+                    float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
+                    if (scale > 1) acc *= scale;
+                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
+                            + off + " normTime=" + normTime + " delta=" + delta
+                            + " scale=" + scale + " acc=" + acc);
+                    acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
+                } else {
+                    // The user is scrolling slowly, so decrease acceleration.
+                    float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
+                    if (scale > 1) acc /= scale;
+                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
+                            + off + " normTime=" + normTime + " delta=" + delta
+                            + " scale=" + scale + " acc=" + acc);
+                    acceleration = acc > 1 ? acc : 1;
+                }
+            }
+            position += off;
+            return Math.abs(position);
+        }
+
+        /**
+         * Generate the number of discrete movement events appropriate for
+         * the currently collected trackball movement.
+         *
+         * @return Returns the number of discrete movements, either positive
+         * or negative, or 0 if there is not enough trackball movement yet
+         * for a discrete movement.
+         */
+        int generate() {
+            int movement = 0;
+            nonAccelMovement = 0;
+            do {
+                final int dir = position >= 0 ? 1 : -1;
+                switch (step) {
+                    // If we are going to execute the first step, then we want
+                    // to do this as soon as possible instead of waiting for
+                    // a full movement, in order to make things look responsive.
+                    case 0:
+                        if (Math.abs(position) < FIRST_MOVEMENT_THRESHOLD) {
+                            return movement;
+                        }
+                        movement += dir;
+                        nonAccelMovement += dir;
+                        step = 1;
+                        break;
+                    // If we have generated the first movement, then we need
+                    // to wait for the second complete trackball motion before
+                    // generating the second discrete movement.
+                    case 1:
+                        if (Math.abs(position) < SECOND_CUMULATIVE_MOVEMENT_THRESHOLD) {
+                            return movement;
+                        }
+                        movement += dir;
+                        nonAccelMovement += dir;
+                        position -= SECOND_CUMULATIVE_MOVEMENT_THRESHOLD * dir;
+                        step = 2;
+                        break;
+                    // After the first two, we generate discrete movements
+                    // consistently with the trackball, applying an acceleration
+                    // if the trackball is moving quickly.  This is a simple
+                    // acceleration on top of what we already compute based
+                    // on how quickly the wheel is being turned, to apply
+                    // a longer increasing acceleration to continuous movement
+                    // in one direction.
+                    default:
+                        if (Math.abs(position) < SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD) {
+                            return movement;
+                        }
+                        movement += dir;
+                        position -= dir * SUBSEQUENT_INCREMENTAL_MOVEMENT_THRESHOLD;
+                        float acc = acceleration;
+                        acc *= 1.1f;
+                        acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
+                        break;
+                }
+            } while (true);
+        }
+    }
+
+    /**
+     * Creates dpad events from unhandled joystick movements.
+     */
+    final class SyntheticJoystickHandler extends Handler {
+        private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
+        private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
+
+        private int mLastXDirection;
+        private int mLastYDirection;
+        private int mLastXKeyCode;
+        private int mLastYKeyCode;
+
+        public SyntheticJoystickHandler() {
+            super(true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ENQUEUE_X_AXIS_KEY_REPEAT:
+                case MSG_ENQUEUE_Y_AXIS_KEY_REPEAT: {
+                    KeyEvent oldEvent = (KeyEvent)msg.obj;
+                    KeyEvent e = KeyEvent.changeTimeRepeat(oldEvent,
+                            SystemClock.uptimeMillis(),
+                            oldEvent.getRepeatCount() + 1);
+                    if (mAttachInfo.mHasWindowFocus) {
+                        enqueueInputEvent(e);
+                        Message m = obtainMessage(msg.what, e);
+                        m.setAsynchronous(true);
+                        sendMessageDelayed(m, ViewConfiguration.getKeyRepeatDelay());
+                    }
+                } break;
             }
         }
 
-        // If there is no view, then the event will not be handled.
-        if (mView == null || !mAdded) {
-            return EVENT_NOT_HANDLED;
+        public void process(MotionEvent event) {
+            update(event, true);
         }
 
-        // Translate the pointer event for compatibility, if needed.
-        if (mTranslator != null) {
-            mTranslator.translateEventInScreenToAppWindow(event);
+        public void cancel(MotionEvent event) {
+            update(event, false);
         }
 
-        // Enter touch mode on down or scroll.
-        final int action = event.getAction();
-        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
-            ensureTouchMode(true);
-        }
+        private void update(MotionEvent event, boolean synthesizeNewKeys) {
+            final long time = event.getEventTime();
+            final int metaState = event.getMetaState();
+            final int deviceId = event.getDeviceId();
+            final int source = event.getSource();
 
-        // Offset the scroll position.
-        if (mCurScrollY != 0) {
-            event.offsetLocation(0, mCurScrollY);
-        }
-        if (MEASURE_LATENCY) {
-            lt.sample("A Dispatching PointerEvents", System.nanoTime() - event.getEventTimeNano());
-        }
+            int xDirection = joystickAxisValueToDirection(
+                    event.getAxisValue(MotionEvent.AXIS_HAT_X));
+            if (xDirection == 0) {
+                xDirection = joystickAxisValueToDirection(event.getX());
+            }
 
-        // Remember the touch position for possible drag-initiation.
-        if (isTouchEvent) {
-            mLastTouchPoint.x = event.getRawX();
-            mLastTouchPoint.y = event.getRawY();
-        }
+            int yDirection = joystickAxisValueToDirection(
+                    event.getAxisValue(MotionEvent.AXIS_HAT_Y));
+            if (yDirection == 0) {
+                yDirection = joystickAxisValueToDirection(event.getY());
+            }
 
-        // Dispatch touch to view hierarchy.
-        boolean handled = mView.dispatchPointerEvent(event);
-        if (MEASURE_LATENCY) {
-            lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
-        }
-        return handled ? EVENT_HANDLED : EVENT_NOT_HANDLED;
-    }
+            if (xDirection != mLastXDirection) {
+                if (mLastXKeyCode != 0) {
+                    removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
+                    enqueueInputEvent(new KeyEvent(time, time,
+                            KeyEvent.ACTION_UP, mLastXKeyCode, 0, metaState,
+                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
+                    mLastXKeyCode = 0;
+                }
 
-    private int deliverTrackballEvent(QueuedInputEvent q) {
-        final MotionEvent event = (MotionEvent)q.mEvent;
-        if (mInputEventConsistencyVerifier != null) {
-            mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
-        }
+                mLastXDirection = xDirection;
 
-        if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
-            if (LOCAL_LOGV)
-                Log.v(TAG, "Dispatching trackball " + event + " to " + mView);
+                if (xDirection != 0 && synthesizeNewKeys) {
+                    mLastXKeyCode = xDirection > 0
+                            ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
+                    final KeyEvent e = new KeyEvent(time, time,
+                            KeyEvent.ACTION_DOWN, mLastXKeyCode, 0, metaState,
+                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
+                    enqueueInputEvent(e);
+                    Message m = obtainMessage(MSG_ENQUEUE_X_AXIS_KEY_REPEAT, e);
+                    m.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
+                }
+            }
 
-            // Dispatch to the IME before propagating down the view hierarchy.
-            // The IME will eventually call back into handleImeFinishedEvent.
-            if (mLastWasImTarget) {
-                InputMethodManager imm = InputMethodManager.peekInstance();
-                if (imm != null) {
-                    final int seq = event.getSequenceNumber();
-                    if (DEBUG_IMF)
-                        Log.v(TAG, "Sending trackball event to IME: seq="
-                                + seq + " event=" + event);
-                    int result = imm.dispatchTrackballEvent(mView.getContext(), seq, event,
-                            mInputMethodCallback);
-                    if (result != EVENT_NOT_HANDLED) {
-                        return result;
-                    }
+            if (yDirection != mLastYDirection) {
+                if (mLastYKeyCode != 0) {
+                    removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
+                    enqueueInputEvent(new KeyEvent(time, time,
+                            KeyEvent.ACTION_UP, mLastYKeyCode, 0, metaState,
+                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
+                    mLastYKeyCode = 0;
+                }
+
+                mLastYDirection = yDirection;
+
+                if (yDirection != 0 && synthesizeNewKeys) {
+                    mLastYKeyCode = yDirection > 0
+                            ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
+                    final KeyEvent e = new KeyEvent(time, time,
+                            KeyEvent.ACTION_DOWN, mLastYKeyCode, 0, metaState,
+                            deviceId, 0, KeyEvent.FLAG_FALLBACK, source);
+                    enqueueInputEvent(e);
+                    Message m = obtainMessage(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT, e);
+                    m.setAsynchronous(true);
+                    sendMessageDelayed(m, ViewConfiguration.getKeyRepeatTimeout());
                 }
             }
         }
 
-        // Not dispatching to IME, continue with post IME actions.
-        return deliverTrackballEventPostIme(q);
+        private int joystickAxisValueToDirection(float value) {
+            if (value >= 0.5f) {
+                return 1;
+            } else if (value <= -0.5f) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
     }
 
-    private int deliverTrackballEventPostIme(QueuedInputEvent q) {
-        final MotionEvent event = (MotionEvent) q.mEvent;
+    /**
+     * Creates dpad events from unhandled touch navigation movements.
+     */
+    final class SyntheticTouchNavigationHandler extends Handler {
+        private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
+        private static final boolean LOCAL_DEBUG = false;
 
-        // If there is no view, then the event will not be handled.
-        if (mView == null || !mAdded) {
-            return EVENT_NOT_HANDLED;
+        // Assumed nominal width and height in millimeters of a touch navigation pad,
+        // if no resolution information is available from the input system.
+        private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
+        private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
+
+        /* TODO: These constants should eventually be moved to ViewConfiguration. */
+
+        // Tap timeout in milliseconds.
+        private static final int TAP_TIMEOUT = 250;
+
+        // The maximum distance traveled for a gesture to be considered a tap in millimeters.
+        private static final int TAP_SLOP_MILLIMETERS = 5;
+
+        // The nominal distance traveled to move by one unit.
+        private static final int TICK_DISTANCE_MILLIMETERS = 12;
+
+        // Minimum and maximum fling velocity in ticks per second.
+        // The minimum velocity should be set such that we perform enough ticks per
+        // second that the fling appears to be fluid.  For example, if we set the minimum
+        // to 2 ticks per second, then there may be up to half a second delay between the next
+        // to last and last ticks which is noticeably discrete and jerky.  This value should
+        // probably not be set to anything less than about 4.
+        // If fling accuracy is a problem then consider tuning the tick distance instead.
+        private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
+        private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
+
+        // Fling velocity decay factor applied after each new key is emitted.
+        // This parameter controls the deceleration and overall duration of the fling.
+        // The fling stops automatically when its velocity drops below the minimum
+        // fling velocity defined above.
+        private static final float FLING_TICK_DECAY = 0.8f;
+
+        /* The input device that we are tracking. */
+
+        private int mCurrentDeviceId = -1;
+        private int mCurrentSource;
+        private boolean mCurrentDeviceSupported;
+
+        /* Configuration for the current input device. */
+
+        // The tap timeout and scaled slop.
+        private int mConfigTapTimeout;
+        private float mConfigTapSlop;
+
+        // The scaled tick distance.  A movement of this amount should generally translate
+        // into a single dpad event in a given direction.
+        private float mConfigTickDistance;
+
+        // The minimum and maximum scaled fling velocity.
+        private float mConfigMinFlingVelocity;
+        private float mConfigMaxFlingVelocity;
+
+        /* Tracking state. */
+
+        // The velocity tracker for detecting flings.
+        private VelocityTracker mVelocityTracker;
+
+        // The active pointer id, or -1 if none.
+        private int mActivePointerId = -1;
+
+        // Time and location where tracking started.
+        private long mStartTime;
+        private float mStartX;
+        private float mStartY;
+
+        // Most recently observed position.
+        private float mLastX;
+        private float mLastY;
+
+        // Accumulated movement delta since the last direction key was sent.
+        private float mAccumulatedX;
+        private float mAccumulatedY;
+
+        // Set to true if any movement was delivered to the app.
+        // Implies that tap slop was exceeded.
+        private boolean mConsumedMovement;
+
+        // The most recently sent key down event.
+        // The keycode remains set until the direction changes or a fling ends
+        // so that repeated key events may be generated as required.
+        private long mPendingKeyDownTime;
+        private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+        private int mPendingKeyRepeatCount;
+        private int mPendingKeyMetaState;
+
+        // The current fling velocity while a fling is in progress.
+        private boolean mFlinging;
+        private float mFlingVelocity;
+
+        public SyntheticTouchNavigationHandler() {
+            super(true);
         }
 
-        // Deliver the trackball event to the view.
-        if (mView.dispatchTrackballEvent(event)) {
-            // If we reach this, we delivered a trackball event to mView and
-            // mView consumed it. Because we will not translate the trackball
-            // event into a key event, touch mode will not exit, so we exit
-            // touch mode here.
-            ensureTouchMode(false);
-            mLastTrackballTime = Integer.MIN_VALUE;
-            return EVENT_HANDLED;
-        }
+        public void process(MotionEvent event) {
+            // Update the current device information.
+            final long time = event.getEventTime();
+            final int deviceId = event.getDeviceId();
+            final int source = event.getSource();
+            if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
+                finishKeys(time);
+                finishTracking(time);
+                mCurrentDeviceId = deviceId;
+                mCurrentSource = source;
+                mCurrentDeviceSupported = false;
+                InputDevice device = event.getDevice();
+                if (device != null) {
+                    // In order to support an input device, we must know certain
+                    // characteristics about it, such as its size and resolution.
+                    InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
+                    InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
+                    if (xRange != null && yRange != null) {
+                        mCurrentDeviceSupported = true;
 
-        // Translate the trackball event into DPAD keys and try to deliver those.
-        final TrackballAxis x = mTrackballAxisX;
-        final TrackballAxis y = mTrackballAxisY;
+                        // Infer the resolution if it not actually known.
+                        float xRes = xRange.getResolution();
+                        if (xRes <= 0) {
+                            xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
+                        }
+                        float yRes = yRange.getResolution();
+                        if (yRes <= 0) {
+                            yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
+                        }
+                        float nominalRes = (xRes + yRes) * 0.5f;
 
-        long curTime = SystemClock.uptimeMillis();
-        if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) {
-            // It has been too long since the last movement,
-            // so restart at the beginning.
-            x.reset(0);
-            y.reset(0);
-            mLastTrackballTime = curTime;
-        }
+                        // Precompute all of the configuration thresholds we will need.
+                        mConfigTapTimeout = TAP_TIMEOUT;
+                        mConfigTapSlop = TAP_SLOP_MILLIMETERS * nominalRes;
+                        mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
+                        mConfigMinFlingVelocity =
+                                MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
+                        mConfigMaxFlingVelocity =
+                                MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
 
-        final int action = event.getAction();
-        final int metaState = event.getMetaState();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                x.reset(2);
-                y.reset(2);
-                enqueueInputEvent(new KeyEvent(curTime, curTime,
-                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
-                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
-                        InputDevice.SOURCE_KEYBOARD));
-                break;
-            case MotionEvent.ACTION_UP:
-                x.reset(2);
-                y.reset(2);
-                enqueueInputEvent(new KeyEvent(curTime, curTime,
-                        KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
-                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
-                        InputDevice.SOURCE_KEYBOARD));
-                break;
-        }
-
-        if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
-                + x.step + " dir=" + x.dir + " acc=" + x.acceleration
-                + " move=" + event.getX()
-                + " / Y=" + y.position + " step="
-                + y.step + " dir=" + y.dir + " acc=" + y.acceleration
-                + " move=" + event.getY());
-        final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
-        final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
-
-        // Generate DPAD events based on the trackball movement.
-        // We pick the axis that has moved the most as the direction of
-        // the DPAD.  When we generate DPAD events for one axis, then the
-        // other axis is reset -- we don't want to perform DPAD jumps due
-        // to slight movements in the trackball when making major movements
-        // along the other axis.
-        int keycode = 0;
-        int movement = 0;
-        float accel = 1;
-        if (xOff > yOff) {
-            movement = x.generate((2/event.getXPrecision()));
-            if (movement != 0) {
-                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
-                        : KeyEvent.KEYCODE_DPAD_LEFT;
-                accel = x.acceleration;
-                y.reset(2);
-            }
-        } else if (yOff > 0) {
-            movement = y.generate((2/event.getYPrecision()));
-            if (movement != 0) {
-                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
-                        : KeyEvent.KEYCODE_DPAD_UP;
-                accel = y.acceleration;
-                x.reset(2);
-            }
-        }
-
-        if (keycode != 0) {
-            if (movement < 0) movement = -movement;
-            int accelMovement = (int)(movement * accel);
-            if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
-                    + " accelMovement=" + accelMovement
-                    + " accel=" + accel);
-            if (accelMovement > movement) {
-                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                        + keycode);
-                movement--;
-                int repeatCount = accelMovement - movement;
-                enqueueInputEvent(new KeyEvent(curTime, curTime,
-                        KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
-                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
-                        InputDevice.SOURCE_KEYBOARD));
-            }
-            while (movement > 0) {
-                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                        + keycode);
-                movement--;
-                curTime = SystemClock.uptimeMillis();
-                enqueueInputEvent(new KeyEvent(curTime, curTime,
-                        KeyEvent.ACTION_DOWN, keycode, 0, metaState,
-                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
-                        InputDevice.SOURCE_KEYBOARD));
-                enqueueInputEvent(new KeyEvent(curTime, curTime,
-                        KeyEvent.ACTION_UP, keycode, 0, metaState,
-                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
-                        InputDevice.SOURCE_KEYBOARD));
-            }
-            mLastTrackballTime = curTime;
-        }
-
-        // Unfortunately we can't tell whether the application consumed the keys, so
-        // we always consider the trackball event handled.
-        return EVENT_HANDLED;
-    }
-
-    private int deliverGenericMotionEvent(QueuedInputEvent q) {
-        final MotionEvent event = (MotionEvent)q.mEvent;
-        if (mInputEventConsistencyVerifier != null) {
-            mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
-        }
-        if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
-            if (LOCAL_LOGV)
-                Log.v(TAG, "Dispatching generic motion " + event + " to " + mView);
-
-            // Dispatch to the IME before propagating down the view hierarchy.
-            // The IME will eventually call back into handleImeFinishedEvent.
-            if (mLastWasImTarget) {
-                InputMethodManager imm = InputMethodManager.peekInstance();
-                if (imm != null) {
-                    final int seq = event.getSequenceNumber();
-                    if (DEBUG_IMF)
-                        Log.v(TAG, "Sending generic motion event to IME: seq="
-                                + seq + " event=" + event);
-                    int result = imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
-                            mInputMethodCallback);
-                    if (result != EVENT_NOT_HANDLED) {
-                        return result;
+                        if (LOCAL_DEBUG) {
+                            Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
+                                    + " (" + Integer.toHexString(mCurrentSource) + "): "
+                                    + "mConfigTapTimeout=" + mConfigTapTimeout
+                                    + ", mConfigTapSlop=" + mConfigTapSlop
+                                    + ", mConfigTickDistance=" + mConfigTickDistance
+                                    + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
+                                    + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
+                        }
                     }
                 }
             }
+            if (!mCurrentDeviceSupported) {
+                return;
+            }
+
+            // Handle the event.
+            final int action = event.getActionMasked();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN: {
+                    boolean caughtFling = mFlinging;
+                    finishKeys(time);
+                    finishTracking(time);
+                    mActivePointerId = event.getPointerId(0);
+                    mVelocityTracker = VelocityTracker.obtain();
+                    mVelocityTracker.addMovement(event);
+                    mStartTime = time;
+                    mStartX = event.getX();
+                    mStartY = event.getY();
+                    mLastX = mStartX;
+                    mLastY = mStartY;
+                    mAccumulatedX = 0;
+                    mAccumulatedY = 0;
+
+                    // If we caught a fling, then pretend that the tap slop has already
+                    // been exceeded to suppress taps whose only purpose is to stop the fling.
+                    mConsumedMovement = caughtFling;
+                    break;
+                }
+
+                case MotionEvent.ACTION_MOVE:
+                case MotionEvent.ACTION_UP: {
+                    if (mActivePointerId < 0) {
+                        break;
+                    }
+                    final int index = event.findPointerIndex(mActivePointerId);
+                    if (index < 0) {
+                        finishKeys(time);
+                        finishTracking(time);
+                        break;
+                    }
+
+                    mVelocityTracker.addMovement(event);
+                    final float x = event.getX(index);
+                    final float y = event.getY(index);
+                    mAccumulatedX += x - mLastX;
+                    mAccumulatedY += y - mLastY;
+                    mLastX = x;
+                    mLastY = y;
+
+                    // Consume any accumulated movement so far.
+                    final int metaState = event.getMetaState();
+                    consumeAccumulatedMovement(time, metaState);
+
+                    // Detect taps and flings.
+                    if (action == MotionEvent.ACTION_UP) {
+                        if (!mConsumedMovement
+                                && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop
+                                && time <= mStartTime + mConfigTapTimeout) {
+                            // It's a tap!
+                            finishKeys(time);
+                            sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
+                            sendKeyUp(time);
+                        } else if (mConsumedMovement
+                                && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                            // It might be a fling.
+                            mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
+                            final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
+                            final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
+                            if (!startFling(time, vx, vy)) {
+                                finishKeys(time);
+                            }
+                        }
+                        finishTracking(time);
+                    }
+                    break;
+                }
+
+                case MotionEvent.ACTION_CANCEL: {
+                    finishKeys(time);
+                    finishTracking(time);
+                    break;
+                }
+            }
         }
 
-        // Not dispatching to IME, continue with post IME actions.
-        return deliverGenericMotionEventPostIme(q);
-    }
-
-    private int deliverGenericMotionEventPostIme(QueuedInputEvent q) {
-        final MotionEvent event = (MotionEvent) q.mEvent;
-        final int source = event.getSource();
-        final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
-        final boolean isTouchPad = (source & InputDevice.SOURCE_CLASS_POSITION) != 0;
-
-        // If there is no view, then the event will not be handled.
-        if (mView == null || !mAdded) {
-            if (isJoystick) {
-                updateJoystickDirection(event, false);
-            } else if (isTouchPad) {
-              mSimulatedDpad.updateTouchPad(this, event, false);
-            }
-            return EVENT_NOT_HANDLED;
-        }
-
-        // Deliver the event to the view.
-        if (mView.dispatchGenericMotionEvent(event)) {
-            if (isJoystick) {
-                updateJoystickDirection(event, false);
-            } else if (isTouchPad) {
-              mSimulatedDpad.updateTouchPad(this, event, false);
-            }
-            return EVENT_HANDLED;
-        }
-
-        if (isJoystick) {
-            // Translate the joystick event into DPAD keys and try to deliver
-            // those.
-            updateJoystickDirection(event, true);
-            return EVENT_HANDLED;
-        }
-        if (isTouchPad) {
-            mSimulatedDpad.updateTouchPad(this, event, true);
-            return EVENT_HANDLED;
-        }
-        return EVENT_NOT_HANDLED;
-    }
-
-    private void updateJoystickDirection(MotionEvent event, boolean synthesizeNewKeys) {
-        final long time = event.getEventTime();
-        final int metaState = event.getMetaState();
-        final int deviceId = event.getDeviceId();
-        final int source = event.getSource();
-
-        int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
-        if (xDirection == 0) {
-            xDirection = joystickAxisValueToDirection(event.getX());
-        }
-
-        int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
-        if (yDirection == 0) {
-            yDirection = joystickAxisValueToDirection(event.getY());
-        }
-
-        if (xDirection != mLastJoystickXDirection) {
-            if (mLastJoystickXKeyCode != 0) {
-                enqueueInputEvent(new KeyEvent(time, time,
-                        KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
-                        deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
-                mLastJoystickXKeyCode = 0;
-            }
-
-            mLastJoystickXDirection = xDirection;
-
-            if (xDirection != 0 && synthesizeNewKeys) {
-                mLastJoystickXKeyCode = xDirection > 0
-                        ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
-                enqueueInputEvent(new KeyEvent(time, time,
-                        KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
-                        deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
+        public void cancel(MotionEvent event) {
+            if (mCurrentDeviceId == event.getDeviceId()
+                    && mCurrentSource == event.getSource()) {
+                final long time = event.getEventTime();
+                finishKeys(time);
+                finishTracking(time);
             }
         }
 
-        if (yDirection != mLastJoystickYDirection) {
-            if (mLastJoystickYKeyCode != 0) {
-                enqueueInputEvent(new KeyEvent(time, time,
-                        KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
-                        deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
-                mLastJoystickYKeyCode = 0;
-            }
+        private void finishKeys(long time) {
+            cancelFling();
+            sendKeyUp(time);
+        }
 
-            mLastJoystickYDirection = yDirection;
-
-            if (yDirection != 0 && synthesizeNewKeys) {
-                mLastJoystickYKeyCode = yDirection > 0
-                        ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
-                enqueueInputEvent(new KeyEvent(time, time,
-                        KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
-                        deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
+        private void finishTracking(long time) {
+            if (mActivePointerId >= 0) {
+                mActivePointerId = -1;
+                mVelocityTracker.recycle();
+                mVelocityTracker = null;
             }
         }
-    }
 
-    private static int joystickAxisValueToDirection(float value) {
-        if (value >= 0.5f) {
-            return 1;
-        } else if (value <= -0.5f) {
-            return -1;
-        } else {
-            return 0;
+        private void consumeAccumulatedMovement(long time, int metaState) {
+            final float absX = Math.abs(mAccumulatedX);
+            final float absY = Math.abs(mAccumulatedY);
+            if (absX >= absY) {
+                if (absX >= mConfigTickDistance) {
+                    mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
+                            KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
+                    mAccumulatedY = 0;
+                    mConsumedMovement = true;
+                }
+            } else {
+                if (absY >= mConfigTickDistance) {
+                    mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
+                            KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
+                    mAccumulatedX = 0;
+                    mConsumedMovement = true;
+                }
+            }
         }
+
+        private float consumeAccumulatedMovement(long time, int metaState,
+                float accumulator, int negativeKeyCode, int positiveKeyCode) {
+            while (accumulator <= -mConfigTickDistance) {
+                sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
+                accumulator += mConfigTickDistance;
+            }
+            while (accumulator >= mConfigTickDistance) {
+                sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
+                accumulator -= mConfigTickDistance;
+            }
+            return accumulator;
+        }
+
+        private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
+            if (mPendingKeyCode != keyCode) {
+                sendKeyUp(time);
+                mPendingKeyDownTime = time;
+                mPendingKeyCode = keyCode;
+                mPendingKeyRepeatCount = 0;
+            } else {
+                mPendingKeyRepeatCount += 1;
+            }
+            mPendingKeyMetaState = metaState;
+
+            // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
+            // but it doesn't quite make sense when simulating the events in this way.
+            if (LOCAL_DEBUG) {
+                Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
+                        + ", repeatCount=" + mPendingKeyRepeatCount
+                        + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
+            }
+            enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
+                    KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
+                    mPendingKeyMetaState, mCurrentDeviceId,
+                    KeyEvent.FLAG_FALLBACK, mCurrentSource));
+        }
+
+        private void sendKeyUp(long time) {
+            if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                if (LOCAL_DEBUG) {
+                    Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
+                            + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
+                }
+                enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
+                        KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
+                        mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
+                        mCurrentSource));
+                mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+            }
+        }
+
+        private boolean startFling(long time, float vx, float vy) {
+            if (LOCAL_DEBUG) {
+                Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
+                        + ", min=" + mConfigMinFlingVelocity);
+            }
+
+            // Flings must be oriented in the same direction as the preceding movements.
+            switch (mPendingKeyCode) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    if (-vx >= mConfigMinFlingVelocity
+                            && Math.abs(vy) < mConfigMinFlingVelocity) {
+                        mFlingVelocity = -vx;
+                        break;
+                    }
+                    return false;
+
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    if (vx >= mConfigMinFlingVelocity
+                            && Math.abs(vy) < mConfigMinFlingVelocity) {
+                        mFlingVelocity = vx;
+                        break;
+                    }
+                    return false;
+
+                case KeyEvent.KEYCODE_DPAD_UP:
+                    if (-vy >= mConfigMinFlingVelocity
+                            && Math.abs(vx) < mConfigMinFlingVelocity) {
+                        mFlingVelocity = -vy;
+                        break;
+                    }
+                    return false;
+
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                    if (vy >= mConfigMinFlingVelocity
+                            && Math.abs(vx) < mConfigMinFlingVelocity) {
+                        mFlingVelocity = vy;
+                        break;
+                    }
+                    return false;
+            }
+
+            // Post the first fling event.
+            mFlinging = postFling(time);
+            return mFlinging;
+        }
+
+        private boolean postFling(long time) {
+            // The idea here is to estimate the time when the pointer would have
+            // traveled one tick distance unit given the current fling velocity.
+            // This effect creates continuity of motion.
+            if (mFlingVelocity >= mConfigMinFlingVelocity) {
+                long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
+                postAtTime(mFlingRunnable, time + delay);
+                if (LOCAL_DEBUG) {
+                    Log.d(LOCAL_TAG, "Posted fling: velocity="
+                            + mFlingVelocity + ", delay=" + delay
+                            + ", keyCode=" + mPendingKeyCode);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        private void cancelFling() {
+            if (mFlinging) {
+                removeCallbacks(mFlingRunnable);
+                mFlinging = false;
+            }
+        }
+
+        private final Runnable mFlingRunnable = new Runnable() {
+            @Override
+            public void run() {
+                final long time = SystemClock.uptimeMillis();
+                sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
+                mFlingVelocity *= FLING_TICK_DECAY;
+                if (!postFling(time)) {
+                    mFlinging = false;
+                    finishKeys(time);
+                }
+            }
+        };
     }
 
     /**
@@ -3736,150 +4813,6 @@
         return false;
     }
 
-    private int deliverKeyEvent(QueuedInputEvent q) {
-        final KeyEvent event = (KeyEvent)q.mEvent;
-        if (mInputEventConsistencyVerifier != null) {
-            mInputEventConsistencyVerifier.onKeyEvent(event, 0);
-        }
-
-        if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
-            if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
-
-            // Perform predispatching before the IME.
-            if (mView.dispatchKeyEventPreIme(event)) {
-                return EVENT_HANDLED;
-            }
-
-            // Dispatch to the IME before propagating down the view hierarchy.
-            // The IME will eventually call back into handleImeFinishedEvent.
-            if (mLastWasImTarget) {
-                InputMethodManager imm = InputMethodManager.peekInstance();
-                if (imm != null) {
-                    final int seq = event.getSequenceNumber();
-                    if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
-                            + seq + " event=" + event);
-                    int result = imm.dispatchKeyEvent(mView.getContext(), seq, event,
-                            mInputMethodCallback);
-                    if (result != EVENT_NOT_HANDLED) {
-                        return result;
-                    }
-                }
-            }
-        }
-
-        // Not dispatching to IME, continue with post IME actions.
-        return deliverKeyEventPostIme(q);
-    }
-
-    private int deliverKeyEventPostIme(QueuedInputEvent q) {
-        final KeyEvent event = (KeyEvent)q.mEvent;
-
-        // If the view went away, then the event will not be handled.
-        if (mView == null || !mAdded) {
-            return EVENT_NOT_HANDLED;
-        }
-
-        // If the key's purpose is to exit touch mode then we consume it and consider it handled.
-        if (checkForLeavingTouchModeAndConsume(event)) {
-            return EVENT_HANDLED;
-        }
-
-        // Make sure the fallback event policy sees all keys that will be delivered to the
-        // view hierarchy.
-        mFallbackEventHandler.preDispatchKeyEvent(event);
-
-        // Deliver the key to the view hierarchy.
-        if (mView.dispatchKeyEvent(event)) {
-            return EVENT_HANDLED;
-        }
-
-        // If the Control modifier is held, try to interpret the key as a shortcut.
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && event.isCtrlPressed()
-                && event.getRepeatCount() == 0
-                && !KeyEvent.isModifierKey(event.getKeyCode())) {
-            if (mView.dispatchKeyShortcutEvent(event)) {
-                return EVENT_HANDLED;
-            }
-        }
-
-        // Apply the fallback event policy.
-        if (mFallbackEventHandler.dispatchKeyEvent(event)) {
-            return EVENT_HANDLED;
-        }
-
-        // Handle automatic focus changes.
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            int direction = 0;
-            switch (event.getKeyCode()) {
-                case KeyEvent.KEYCODE_DPAD_LEFT:
-                    if (event.hasNoModifiers()) {
-                        direction = View.FOCUS_LEFT;
-                    }
-                    break;
-                case KeyEvent.KEYCODE_DPAD_RIGHT:
-                    if (event.hasNoModifiers()) {
-                        direction = View.FOCUS_RIGHT;
-                    }
-                    break;
-                case KeyEvent.KEYCODE_DPAD_UP:
-                    if (event.hasNoModifiers()) {
-                        direction = View.FOCUS_UP;
-                    }
-                    break;
-                case KeyEvent.KEYCODE_DPAD_DOWN:
-                    if (event.hasNoModifiers()) {
-                        direction = View.FOCUS_DOWN;
-                    }
-                    break;
-                case KeyEvent.KEYCODE_TAB:
-                    if (event.hasNoModifiers()) {
-                        direction = View.FOCUS_FORWARD;
-                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                        direction = View.FOCUS_BACKWARD;
-                    }
-                    break;
-            }
-            if (direction != 0) {
-                View focused = mView.findFocus();
-                if (focused != null) {
-                    View v = focused.focusSearch(direction);
-                    if (v != null && v != focused) {
-                        // do the math the get the interesting rect
-                        // of previous focused into the coord system of
-                        // newly focused view
-                        focused.getFocusedRect(mTempRect);
-                        if (mView instanceof ViewGroup) {
-                            ((ViewGroup) mView).offsetDescendantRectToMyCoords(
-                                    focused, mTempRect);
-                            ((ViewGroup) mView).offsetRectIntoDescendantCoords(
-                                    v, mTempRect);
-                        }
-                        if (v.requestFocus(direction, mTempRect)) {
-                            playSoundEffect(SoundEffectConstants
-                                    .getContantForFocusDirection(direction));
-                            return EVENT_HANDLED;
-                        }
-                    }
-
-                    // Give the focused view a last chance to handle the dpad key.
-                    if (mView.dispatchUnhandledMove(focused, direction)) {
-                        return EVENT_HANDLED;
-                    }
-                } else {
-                    // find the best view to give focus to in this non-touch-mode with no-focus
-                    View v = focusSearch(null, direction);
-                    if (v != null && v.requestFocus(direction)) {
-                        return EVENT_HANDLED;
-                    }
-                }
-            }
-        }
-
-        // Key was unhandled.
-        return EVENT_NOT_HANDLED;
-    }
-
     /* drag/drop */
     void setLocalDragState(Object obj) {
         mLocalDragState = obj;
@@ -4257,14 +5190,6 @@
         }
     }
 
-    void dispatchImeFinishedEvent(int seq, boolean handled) {
-        Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT);
-        msg.arg1 = seq;
-        msg.arg2 = handled ? 1 : 0;
-        msg.setAsynchronous(true);
-        mHandler.sendMessage(msg);
-    }
-
     public void dispatchFinishInputConnection(InputConnection connection) {
         Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
         mHandler.sendMessage(msg);
@@ -4319,13 +5244,25 @@
      * needing a queue on the application's side.
      */
     private static final class QueuedInputEvent {
-        public static final int FLAG_DELIVER_POST_IME = 1;
+        public static final int FLAG_DELIVER_POST_IME = 1 << 0;
+        public static final int FLAG_DEFERRED = 1 << 1;
+        public static final int FLAG_FINISHED = 1 << 2;
+        public static final int FLAG_FINISHED_HANDLED = 1 << 3;
+        public static final int FLAG_RESYNTHESIZED = 1 << 4;
 
         public QueuedInputEvent mNext;
 
         public InputEvent mEvent;
         public InputEventReceiver mReceiver;
         public int mFlags;
+
+        public boolean shouldSkipIme() {
+            if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
+                return true;
+            }
+            return mEvent instanceof MotionEvent
+                    && mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER);
+        }
     }
 
     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
@@ -4369,15 +5306,17 @@
         // in response to touch events and we want to ensure that the injected keys
         // are processed in the order they were received and we cannot trust that
         // the time stamp of injected events are monotonic.
-        QueuedInputEvent last = mFirstPendingInputEvent;
+        QueuedInputEvent last = mPendingInputEventTail;
         if (last == null) {
-            mFirstPendingInputEvent = q;
+            mPendingInputEventHead = q;
+            mPendingInputEventTail = q;
         } else {
-            while (last.mNext != null) {
-                last = last.mNext;
-            }
             last.mNext = q;
+            mPendingInputEventTail = q;
         }
+        mPendingInputEventCount += 1;
+        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
+                mPendingInputEventCount);
 
         if (processImmediately) {
             doProcessInputEvents();
@@ -4396,16 +5335,20 @@
     }
 
     void doProcessInputEvents() {
-        while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) {
-            QueuedInputEvent q = mFirstPendingInputEvent;
-            mFirstPendingInputEvent = q.mNext;
-            q.mNext = null;
-            mCurrentInputEvent = q;
-
-            final int result = deliverInputEvent(q);
-            if (result != EVENT_IN_PROGRESS) {
-                finishCurrentInputEvent(result == EVENT_HANDLED);
+        // Deliver all pending input events in the queue.
+        while (mPendingInputEventHead != null) {
+            QueuedInputEvent q = mPendingInputEventHead;
+            mPendingInputEventHead = q.mNext;
+            if (mPendingInputEventHead == null) {
+                mPendingInputEventTail = null;
             }
+            q.mNext = null;
+
+            mPendingInputEventCount -= 1;
+            Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
+                    mPendingInputEventCount);
+
+            deliverInputEvent(q);
         }
 
         // We are done processing all input events that we can process right now
@@ -4416,44 +5359,27 @@
         }
     }
 
-    void handleImeFinishedEvent(int seq, boolean handled) {
-        final QueuedInputEvent q = mCurrentInputEvent;
-        if (q != null && q.mEvent.getSequenceNumber() == seq) {
-            if (DEBUG_IMF) {
-                Log.v(TAG, "IME finished event: seq=" + seq
-                        + " handled=" + handled + " event=" + q);
+    private void deliverInputEvent(QueuedInputEvent q) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
+        try {
+            if (mInputEventConsistencyVerifier != null) {
+                mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
             }
 
-            if (!handled) {
-                // If the window doesn't currently have input focus, then drop
-                // this event.  This could be an event that came back from the
-                // IME dispatch but the window has lost focus in the meantime.
-                if (!mAttachInfo.mHasWindowFocus && !isTerminalInputEvent(q.mEvent)) {
-                    Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
-                } else {
-                    final int result = deliverInputEventPostIme(q);
-                    if (result == EVENT_HANDLED) {
-                        handled = true;
-                    }
-                }
+            InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+            if (stage != null) {
+                stage.deliver(q);
+            } else {
+                finishInputEvent(q);
             }
-            finishCurrentInputEvent(handled);
-
-            // Immediately start processing the next input event.
-            doProcessInputEvents();
-        } else {
-            if (DEBUG_IMF) {
-                Log.v(TAG, "IME finished event: seq=" + seq
-                        + " handled=" + handled + ", event not found!");
-            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
     }
 
-    private void finishCurrentInputEvent(boolean handled) {
-        final QueuedInputEvent q = mCurrentInputEvent;
-        mCurrentInputEvent = null;
-
+    private void finishInputEvent(QueuedInputEvent q) {
         if (q.mReceiver != null) {
+            boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
             q.mReceiver.finishInputEvent(q.mEvent, handled);
         } else {
             q.mEvent.recycleIfNeededAfterDispatch();
@@ -4462,7 +5388,7 @@
         recycleQueuedInputEvent(q);
     }
 
-    private static boolean isTerminalInputEvent(InputEvent event) {
+    static boolean isTerminalInputEvent(InputEvent event) {
         if (event instanceof KeyEvent) {
             final KeyEvent keyEvent = (KeyEvent)event;
             return keyEvent.getAction() == KeyEvent.ACTION_UP;
@@ -4998,22 +5924,6 @@
             ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn);
         }
     }
-    
-    static final class InputMethodCallback implements InputMethodManager.FinishedEventCallback {
-        private WeakReference<ViewRootImpl> mViewAncestor;
-
-        public InputMethodCallback(ViewRootImpl viewAncestor) {
-            mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
-        }
-
-        @Override
-        public void finishedEvent(int seq, boolean handled) {
-            final ViewRootImpl viewAncestor = mViewAncestor.get();
-            if (viewAncestor != null) {
-                viewAncestor.dispatchImeFinishedEvent(seq, handled);
-            }
-        }
-    }
 
     static class W extends IWindow.Stub {
         private final WeakReference<ViewRootImpl> mViewAncestor;
@@ -5161,176 +6071,6 @@
         }
     }
 
-    /**
-     * Maintains state information for a single trackball axis, generating
-     * discrete (DPAD) movements based on raw trackball motion.
-     */
-    static final class TrackballAxis {
-        /**
-         * The maximum amount of acceleration we will apply.
-         */
-        static final float MAX_ACCELERATION = 20;
-
-        /**
-         * The maximum amount of time (in milliseconds) between events in order
-         * for us to consider the user to be doing fast trackball movements,
-         * and thus apply an acceleration.
-         */
-        static final long FAST_MOVE_TIME = 150;
-
-        /**
-         * Scaling factor to the time (in milliseconds) between events to how
-         * much to multiple/divide the current acceleration.  When movement
-         * is < FAST_MOVE_TIME this multiplies the acceleration; when >
-         * FAST_MOVE_TIME it divides it.
-         */
-        static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
-
-        float position;
-        float absPosition;
-        float acceleration = 1;
-        long lastMoveTime = 0;
-        int step;
-        int dir;
-        int nonAccelMovement;
-
-        void reset(int _step) {
-            position = 0;
-            acceleration = 1;
-            lastMoveTime = 0;
-            step = _step;
-            dir = 0;
-        }
-
-        /**
-         * Add trackball movement into the state.  If the direction of movement
-         * has been reversed, the state is reset before adding the
-         * movement (so that you don't have to compensate for any previously
-         * collected movement before see the result of the movement in the
-         * new direction).
-         *
-         * @return Returns the absolute value of the amount of movement
-         * collected so far.
-         */
-        float collect(float off, long time, String axis) {
-            long normTime;
-            if (off > 0) {
-                normTime = (long)(off * FAST_MOVE_TIME);
-                if (dir < 0) {
-                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to positive!");
-                    position = 0;
-                    step = 0;
-                    acceleration = 1;
-                    lastMoveTime = 0;
-                }
-                dir = 1;
-            } else if (off < 0) {
-                normTime = (long)((-off) * FAST_MOVE_TIME);
-                if (dir > 0) {
-                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " reversed to negative!");
-                    position = 0;
-                    step = 0;
-                    acceleration = 1;
-                    lastMoveTime = 0;
-                }
-                dir = -1;
-            } else {
-                normTime = 0;
-            }
-
-            // The number of milliseconds between each movement that is
-            // considered "normal" and will not result in any acceleration
-            // or deceleration, scaled by the offset we have here.
-            if (normTime > 0) {
-                long delta = time - lastMoveTime;
-                lastMoveTime = time;
-                float acc = acceleration;
-                if (delta < normTime) {
-                    // The user is scrolling rapidly, so increase acceleration.
-                    float scale = (normTime-delta) * ACCEL_MOVE_SCALING_FACTOR;
-                    if (scale > 1) acc *= scale;
-                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " accelerate: off="
-                            + off + " normTime=" + normTime + " delta=" + delta
-                            + " scale=" + scale + " acc=" + acc);
-                    acceleration = acc < MAX_ACCELERATION ? acc : MAX_ACCELERATION;
-                } else {
-                    // The user is scrolling slowly, so decrease acceleration.
-                    float scale = (delta-normTime) * ACCEL_MOVE_SCALING_FACTOR;
-                    if (scale > 1) acc /= scale;
-                    if (DEBUG_TRACKBALL) Log.v(TAG, axis + " deccelerate: off="
-                            + off + " normTime=" + normTime + " delta=" + delta
-                            + " scale=" + scale + " acc=" + acc);
-                    acceleration = acc > 1 ? acc : 1;
-                }
-            }
-            position += off;
-            return (absPosition = Math.abs(position));
-        }
-
-        /**
-         * Generate the number of discrete movement events appropriate for
-         * the currently collected trackball movement.
-         *
-         * @param precision The minimum movement required to generate the
-         * first discrete movement.
-         *
-         * @return Returns the number of discrete movements, either positive
-         * or negative, or 0 if there is not enough trackball movement yet
-         * for a discrete movement.
-         */
-        int generate(float precision) {
-            int movement = 0;
-            nonAccelMovement = 0;
-            do {
-                final int dir = position >= 0 ? 1 : -1;
-                switch (step) {
-                    // If we are going to execute the first step, then we want
-                    // to do this as soon as possible instead of waiting for
-                    // a full movement, in order to make things look responsive.
-                    case 0:
-                        if (absPosition < precision) {
-                            return movement;
-                        }
-                        movement += dir;
-                        nonAccelMovement += dir;
-                        step = 1;
-                        break;
-                    // If we have generated the first movement, then we need
-                    // to wait for the second complete trackball motion before
-                    // generating the second discrete movement.
-                    case 1:
-                        if (absPosition < 2) {
-                            return movement;
-                        }
-                        movement += dir;
-                        nonAccelMovement += dir;
-                        position += dir > 0 ? -2 : 2;
-                        absPosition = Math.abs(position);
-                        step = 2;
-                        break;
-                    // After the first two, we generate discrete movements
-                    // consistently with the trackball, applying an acceleration
-                    // if the trackball is moving quickly.  This is a simple
-                    // acceleration on top of what we already compute based
-                    // on how quickly the wheel is being turned, to apply
-                    // a longer increasing acceleration to continuous movement
-                    // in one direction.
-                    default:
-                        if (absPosition < 1) {
-                            return movement;
-                        }
-                        movement += dir;
-                        position += dir >= 0 ? -1 : 1;
-                        absPosition = Math.abs(position);
-                        float acc = acceleration;
-                        acc *= 1.1f;
-                        acceleration = acc < MAX_ACCELERATION ? acc : acceleration;
-                        break;
-                }
-            } while (true);
-        }
-    }
-
     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
         public CalledFromWrongThreadException(String msg) {
             super(msg);
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index cfcf3c0..072c95f 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -33,6 +33,8 @@
  */
 public final class ViewTreeObserver {
     // Recursive listeners use CopyOnWriteArrayList
+    private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners;
+    private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners;
     private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
     private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
 
@@ -49,6 +51,36 @@
     private boolean mAlive = true;
 
     /**
+     * Interface definition for a callback to be invoked when the view hierarchy is
+     * attached to and detached from its window.
+     */
+    public interface OnWindowAttachListener {
+        /**
+         * Callback method to be invoked when the view hierarchy is attached to a window
+         */
+        public void onWindowAttached();
+
+        /**
+         * Callback method to be invoked when the view hierarchy is detached from a window
+         */
+        public void onWindowDetached();
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when the view hierarchy's window
+     * focus state changes.
+     */
+    public interface OnWindowFocusChangeListener {
+        /**
+         * Callback method to be invoked when the window focus changes in the view tree.
+         *
+         * @param hasFocus Set to true if the window is gaining focus, false if it is
+         * losing focus.
+         */
+        public void onWindowFocusChanged(boolean hasFocus);
+    }
+
+    /**
      * Interface definition for a callback to be invoked when the focus state within
      * the view tree changes.
      */
@@ -272,6 +304,22 @@
      * @param observer The ViewTreeObserver whose listeners must be added to this observer
      */
     void merge(ViewTreeObserver observer) {
+        if (observer.mOnWindowAttachListeners != null) {
+            if (mOnWindowAttachListeners != null) {
+                mOnWindowAttachListeners.addAll(observer.mOnWindowAttachListeners);
+            } else {
+                mOnWindowAttachListeners = observer.mOnWindowAttachListeners;
+            }
+        }
+
+        if (observer.mOnWindowFocusListeners != null) {
+            if (mOnWindowFocusListeners != null) {
+                mOnWindowFocusListeners.addAll(observer.mOnWindowFocusListeners);
+            } else {
+                mOnWindowFocusListeners = observer.mOnWindowFocusListeners;
+            }
+        }
+
         if (observer.mOnGlobalFocusListeners != null) {
             if (mOnGlobalFocusListeners != null) {
                 mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
@@ -324,6 +372,76 @@
     }
 
     /**
+     * Register a callback to be invoked when the view hierarchy is attached to a window.
+     *
+     * @param listener The callback to add
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     */
+    public void addOnWindowAttachListener(OnWindowAttachListener listener) {
+        checkIsAlive();
+
+        if (mOnWindowAttachListeners == null) {
+            mOnWindowAttachListeners
+                    = new CopyOnWriteArrayList<OnWindowAttachListener>();
+        }
+
+        mOnWindowAttachListeners.add(listener);
+    }
+
+    /**
+     * Remove a previously installed window attach callback.
+     *
+     * @param victim The callback to remove
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     *
+     * @see #addOnWindowAttachListener(android.view.ViewTreeObserver.OnWindowAttachListener)
+     */
+    public void removeOnWindowAttachListener(OnWindowAttachListener victim) {
+        checkIsAlive();
+        if (mOnWindowAttachListeners == null) {
+            return;
+        }
+        mOnWindowAttachListeners.remove(victim);
+    }
+
+    /**
+     * Register a callback to be invoked when the window focus state within the view tree changes.
+     *
+     * @param listener The callback to add
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     */
+    public void addOnWindowFocusChangeListener(OnWindowFocusChangeListener listener) {
+        checkIsAlive();
+
+        if (mOnWindowFocusListeners == null) {
+            mOnWindowFocusListeners
+                    = new CopyOnWriteArrayList<OnWindowFocusChangeListener>();
+        }
+
+        mOnWindowFocusListeners.add(listener);
+    }
+
+    /**
+     * Remove a previously installed window focus change callback.
+     *
+     * @param victim The callback to remove
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     *
+     * @see #addOnWindowFocusChangeListener(android.view.ViewTreeObserver.OnWindowFocusChangeListener)
+     */
+    public void removeOnWindowFocusChangeListener(OnWindowFocusChangeListener victim) {
+        checkIsAlive();
+        if (mOnWindowFocusListeners == null) {
+            return;
+        }
+        mOnWindowFocusListeners.remove(victim);
+    }
+
+    /**
      * Register a callback to be invoked when the focus state within the view tree changes.
      *
      * @param listener The callback to add
@@ -621,6 +739,41 @@
     }
 
     /**
+     * Notifies registered listeners that window has been attached/detached.
+     */
+    final void dispatchOnWindowAttachedChange(boolean attached) {
+        // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+        // perform the dispatching. The iterator is a safe guard against listeners that
+        // could mutate the list by calling the various add/remove methods. This prevents
+        // the array from being modified while we iterate it.
+        final CopyOnWriteArrayList<OnWindowAttachListener> listeners
+                = mOnWindowAttachListeners;
+        if (listeners != null && listeners.size() > 0) {
+            for (OnWindowAttachListener listener : listeners) {
+                if (attached) listener.onWindowAttached();
+                else listener.onWindowDetached();
+            }
+        }
+    }
+
+    /**
+     * Notifies registered listeners that window focus has changed.
+     */
+    final void dispatchOnWindowFocusChange(boolean hasFocus) {
+        // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+        // perform the dispatching. The iterator is a safe guard against listeners that
+        // could mutate the list by calling the various add/remove methods. This prevents
+        // the array from being modified while we iterate it.
+        final CopyOnWriteArrayList<OnWindowFocusChangeListener> listeners
+                = mOnWindowFocusListeners;
+        if (listeners != null && listeners.size() > 0) {
+            for (OnWindowFocusChangeListener listener : listeners) {
+                listener.onWindowFocusChanged(hasFocus);
+            }
+        }
+    }
+
+    /**
      * Notifies registered listeners that focus has changed.
      */
     final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index e711b94..9c00b7f 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -468,7 +468,8 @@
         // Force reloading the image resource
         sc.icon.setImageDrawable(null);
         sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
-        if (sc.streamType == AudioManager.STREAM_RING &&
+        if (((sc.streamType == AudioManager.STREAM_RING) ||
+                (sc.streamType == AudioManager.STREAM_NOTIFICATION)) &&
                 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
             sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 792188b..96ef0b4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -272,7 +272,7 @@
         public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
     
         /**
-         * Window type: window for showing media (e.g. video).  These windows
+         * Window type: window for showing media (such as video).  These windows
          * are displayed behind their attached window.
          */
         public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
@@ -584,14 +584,14 @@
         /** Window flag: this window can never receive touch events. */
         public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;
         
-        /** Window flag: Even when this window is focusable (its
-         * {@link #FLAG_NOT_FOCUSABLE is not set), allow any pointer events
+        /** Window flag: even when this window is focusable (its
+         * {@link #FLAG_NOT_FOCUSABLE} is not set), allow any pointer events
          * outside of the window to be sent to the windows behind it.  Otherwise
          * it will consume all pointer events itself, regardless of whether they
          * are inside of the window. */
         public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;
         
-        /** Window flag: When set, if the device is asleep when the touch
+        /** Window flag: when set, if the device is asleep when the touch
          * screen is pressed, you will receive this first touch event.  Usually
          * the first touch event is consumed by the system since the user can
          * not see what they are pressing on.
@@ -603,7 +603,7 @@
         public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;
         
         /** Window flag: place the window within the entire screen, ignoring
-         *  decorations around the border (a.k.a. the status bar).  The
+         *  decorations around the border (such as the status bar).  The
          *  window must correctly position its contents to take the screen
          *  decoration into account.  This flag is normally set for you
          *  by Window as described in {@link Window#setFlags}. */
@@ -613,7 +613,7 @@
         public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;
         
         /**
-         * Window flag: Hide all screen decorations (e.g. status bar) while
+         * Window flag: hide all screen decorations (such as the status bar) while
          * this window is displayed.  This allows the window to use the entire
          * display space for itself -- the status bar will be hidden when
          * an app window with this flag set is on the top layer.
@@ -631,8 +631,8 @@
          */
         public static final int FLAG_FULLSCREEN      = 0x00000400;
         
-        /** Window flag: Override {@link #FLAG_FULLSCREEN and force the
-         *  screen decorations (such as status bar) to be shown. */
+        /** Window flag: override {@link #FLAG_FULLSCREEN} and force the
+         *  screen decorations (such as the status bar) to be shown. */
         public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;
         
         /** Window flag: turn on dithering when compositing this window to
@@ -641,7 +641,7 @@
         @Deprecated
         public static final int FLAG_DITHER             = 0x00001000;
         
-        /** Window flag: Treat the content of the window as secure, preventing
+        /** Window flag: treat the content of the window as secure, preventing
          * it from appearing in screenshots or from being viewed on non-secure
          * displays.
          *
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 7eb26fa..0ff46e9 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -136,11 +136,11 @@
         }
     }
 
-    public static IWindowSession getWindowSession(Looper mainLooper) {
+    public static IWindowSession getWindowSession() {
         synchronized (WindowManagerGlobal.class) {
             if (sWindowSession == null) {
                 try {
-                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
+                    InputMethodManager imm = InputMethodManager.getInstance();
                     IWindowManager windowManager = getWindowManagerService();
                     sWindowSession = windowManager.openSession(
                             imm.getClient(), imm.getInputContext());
@@ -351,7 +351,7 @@
         View view = root.getView();
 
         if (view != null) {
-            InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
+            InputMethodManager imm = InputMethodManager.getInstance();
             if (imm != null) {
                 imm.windowDismissed(mViews[index].getWindowToken());
             }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index d258f4d..4df4734 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -19,7 +19,6 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.view.IInputConnectionWrapper;
 import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
@@ -35,15 +34,20 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
-import android.os.SystemClock;
+import android.os.Trace;
 import android.text.style.SuggestionSpan;
 import android.util.Log;
+import android.util.Pools.Pool;
+import android.util.Pools.SimplePool;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventSender;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewRootImpl;
+import android.util.SparseArray;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -199,8 +203,9 @@
     static final boolean DEBUG = false;
     static final String TAG = "InputMethodManager";
 
-    static final Object mInstanceSync = new Object();
-    static InputMethodManager mInstance;
+    static final String PENDING_EVENT_COUNTER = "aq:imm";
+
+    static InputMethodManager sInstance;
 
     /**
      * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
@@ -231,7 +236,14 @@
      */
     static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT = 2500;
 
-    private static final int MAX_PENDING_EVENT_POOL_SIZE = 4;
+    /** @hide */
+    public static final int DISPATCH_IN_PROGRESS = -1;
+
+    /** @hide */
+    public static final int DISPATCH_NOT_HANDLED = 0;
+
+    /** @hide */
+    public static final int DISPATCH_HANDLED = 1;
 
     final IInputMethodManager mService;
     final Looper mMainLooper;
@@ -319,10 +331,11 @@
      * The actual instance of the method to make calls on it.
      */
     IInputMethodSession mCurMethod;
+    InputChannel mCurChannel;
+    ImeInputEventSender mCurSender;
 
-    PendingEvent mPendingEventPool;
-    int mPendingEventPoolSize;
-    PendingEvent mFirstPendingEvent;
+    final Pool<PendingEvent> mPendingEventPool = new SimplePool<PendingEvent>(20);
+    final SparseArray<PendingEvent> mPendingEvents = new SparseArray<PendingEvent>(20);
 
     // -----------------------------------------------------------
     
@@ -330,8 +343,10 @@
     static final int MSG_BIND = 2;
     static final int MSG_UNBIND = 3;
     static final int MSG_SET_ACTIVE = 4;
-    static final int MSG_EVENT_TIMEOUT = 5;
-    
+    static final int MSG_SEND_INPUT_EVENT = 5;
+    static final int MSG_TIMEOUT_INPUT_EVENT = 6;
+    static final int MSG_FLUSH_INPUT_EVENT = 7;
+
     class H extends Handler {
         H(Looper looper) {
             super(looper, null, true);
@@ -363,9 +378,13 @@
                         if (mBindSequence < 0 || mBindSequence != res.sequence) {
                             Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
                                     + ", given seq=" + res.sequence);
+                            if (res.channel != null && res.channel != mCurChannel) {
+                                res.channel.dispose();
+                            }
                             return;
                         }
-                        
+
+                        setInputChannelLocked(res.channel);
                         mCurMethod = res.method;
                         mCurId = res.id;
                         mBindSequence = res.sequence;
@@ -445,15 +464,16 @@
                     }
                     return;
                 }
-                case MSG_EVENT_TIMEOUT: {
-                    // Even though the message contains both the sequence number
-                    // and the PendingEvent object itself, we only pass the
-                    // sequence number to the timeoutEvent function because it's
-                    // possible for the PendingEvent object to be dequeued and
-                    // recycled concurrently.  To avoid a possible race, we make
-                    // a point of always looking up the PendingEvent within the
-                    // queue given only the sequence number of the event.
-                    timeoutEvent(msg.arg1);
+                case MSG_SEND_INPUT_EVENT: {
+                    sendInputEventAndReportResultOnMainLooper((PendingEvent)msg.obj);
+                    return;
+                }
+                case MSG_TIMEOUT_INPUT_EVENT: {
+                    finishedInputEvent(msg.arg1, false, true);
+                    return;
+                }
+                case MSG_FLUSH_INPUT_EVENT: {
+                    finishedInputEvent(msg.arg1, false, false);
                     return;
                 }
             }
@@ -482,10 +502,10 @@
     }
     
     final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
-        @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
             // No need to check for dump permission, since we only give this
             // interface to the system.
-            
             CountDownLatch latch = new CountDownLatch(1);
             SomeArgs sargs = SomeArgs.obtain();
             sargs.arg1 = fd;
@@ -501,47 +521,35 @@
                 fout.println("Interrupted waiting for dump");
             }
         }
-        
+
+        @Override
         public void setUsingInputMethod(boolean state) {
         }
-        
+
+        @Override
         public void onBindMethod(InputBindResult res) {
             mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
         }
-        
+
+        @Override
         public void onUnbindMethod(int sequence) {
             mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, 0));
         }
-        
+
+        @Override
         public void setActive(boolean active) {
             mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
         }
-    };    
-    
+    };
+
     final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
 
-    final IInputMethodCallback mInputMethodCallback = new IInputMethodCallback.Stub() {
-        @Override
-        public void finishedEvent(int seq, boolean handled) {
-            InputMethodManager.this.finishedEvent(seq, handled);
-        }
-
-        @Override
-        public void sessionCreated(IInputMethodSession session) {
-            // Stub -- not for use in the client.
-        }
-    };
-    
     InputMethodManager(IInputMethodManager service, Looper looper) {
         mService = service;
         mMainLooper = looper;
         mH = new H(looper);
         mIInputContext = new ControlledInputConnectionWrapper(looper,
                 mDummyInputConnection, this);
-        
-        if (mInstance == null) {
-            mInstance = this;
-        }
     }
 
     /**
@@ -549,25 +557,15 @@
      * doesn't already exist.
      * @hide
      */
-    static public InputMethodManager getInstance(Context context) {
-        return getInstance(context.getMainLooper());
-    }
-    
-    /**
-     * Internally, the input method manager can't be context-dependent, so
-     * we have this here for the places that need it.
-     * @hide
-     */
-    static public InputMethodManager getInstance(Looper mainLooper) {
-        synchronized (mInstanceSync) {
-            if (mInstance != null) {
-                return mInstance;
+    public static InputMethodManager getInstance() {
+        synchronized (InputMethodManager.class) {
+            if (sInstance == null) {
+                IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
+                IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
+                sInstance = new InputMethodManager(service, Looper.getMainLooper());
             }
-            IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
-            IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
-            mInstance = new InputMethodManager(service, mainLooper);
+            return sInstance;
         }
-        return mInstance;
     }
     
     /**
@@ -575,8 +573,8 @@
      * if it exists.
      * @hide
      */
-    static public InputMethodManager peekInstance() {
-        return mInstance;
+    public static InputMethodManager peekInstance() {
+        return sInstance;
     }
     
     /** @hide */
@@ -716,11 +714,26 @@
      */
     void clearBindingLocked() {
         clearConnectionLocked();
+        setInputChannelLocked(null);
         mBindSequence = -1;
         mCurId = null;
         mCurMethod = null;
     }
-    
+
+    void setInputChannelLocked(InputChannel channel) {
+        if (mCurChannel != channel) {
+            if (mCurSender != null) {
+                flushPendingEventsLocked();
+                mCurSender.dispose();
+                mCurSender = null;
+            }
+            if (mCurChannel != null) {
+                mCurChannel.dispose();
+            }
+            mCurChannel = channel;
+        }
+    }
+
     /**
      * Reset all of the state associated with a served view being connected
      * to an input method
@@ -1090,6 +1103,7 @@
             // we need to reschedule our work for over there.
             if (DEBUG) Log.v(TAG, "Starting input: reschedule to view thread");
             vh.post(new Runnable() {
+                @Override
                 public void run() {
                     startInputInner(null, 0, 0, 0);
                 }
@@ -1161,13 +1175,19 @@
                 if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
                 if (res != null) {
                     if (res.id != null) {
+                        setInputChannelLocked(res.channel);
                         mBindSequence = res.sequence;
                         mCurMethod = res.method;
                         mCurId = res.id;
-                    } else if (mCurMethod == null) {
-                        // This means there is no input method available.
-                        if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
-                        return true;
+                    } else {
+                        if (res.channel != null && res.channel != mCurChannel) {
+                            res.channel.dispose();
+                        }
+                        if (mCurMethod == null) {
+                            // This means there is no input method available.
+                            if (DEBUG) Log.v(TAG, "ABORT input: no input method!");
+                            return true;
+                        }
                     }
                 }
                 if (mCurMethod != null && mCompletions != null) {
@@ -1561,172 +1581,159 @@
             throw new RuntimeException(e);
         }
     }
-    
+
     /**
+     * Dispatches an input event to the IME.
+     *
+     * Returns {@link #DISPATCH_HANDLED} if the event was handled.
+     * Returns {@link #DISPATCH_NOT_HANDLED} if the event was not handled.
+     * Returns {@link #DISPATCH_IN_PROGRESS} if the event is in progress and the
+     * callback will be invoked later.
+     *
      * @hide
      */
-    public int dispatchKeyEvent(Context context, int seq, KeyEvent key,
-            FinishedEventCallback callback) {
+    public int dispatchInputEvent(InputEvent event, Object token,
+            FinishedInputEventCallback callback, Handler handler) {
         synchronized (mH) {
-            if (DEBUG) Log.d(TAG, "dispatchKeyEvent");
-
             if (mCurMethod != null) {
-                if (key.getAction() == KeyEvent.ACTION_DOWN
-                        && key.getKeyCode() == KeyEvent.KEYCODE_SYM
-                        && key.getRepeatCount() == 0) {
-                    showInputMethodPickerLocked();
-                    return ViewRootImpl.EVENT_HANDLED;
+                if (event instanceof KeyEvent) {
+                    KeyEvent keyEvent = (KeyEvent)event;
+                    if (keyEvent.getAction() == KeyEvent.ACTION_DOWN
+                            && keyEvent.getKeyCode() == KeyEvent.KEYCODE_SYM
+                            && keyEvent.getRepeatCount() == 0) {
+                        showInputMethodPickerLocked();
+                        return DISPATCH_HANDLED;
+                    }
                 }
-                try {
-                    if (DEBUG) Log.v(TAG, "DISPATCH KEY: " + mCurMethod);
-                    final long startTime = SystemClock.uptimeMillis();
-                    enqueuePendingEventLocked(startTime, seq, mCurId, callback);
-                    mCurMethod.dispatchKeyEvent(seq, key, mInputMethodCallback);
-                    return ViewRootImpl.EVENT_IN_PROGRESS;
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId + " dropping: " + key, e);
+
+                if (DEBUG) Log.v(TAG, "DISPATCH INPUT EVENT: " + mCurMethod);
+
+                PendingEvent p = obtainPendingEventLocked(
+                        event, token, mCurId, callback, handler);
+                if (mMainLooper.isCurrentThread()) {
+                    // Already running on the IMM thread so we can send the event immediately.
+                    return sendInputEventOnMainLooperLocked(p);
                 }
+
+                // Post the event to the IMM thread.
+                Message msg = mH.obtainMessage(MSG_SEND_INPUT_EVENT, p);
+                msg.setAsynchronous(true);
+                mH.sendMessage(msg);
+                return DISPATCH_IN_PROGRESS;
             }
         }
-        return ViewRootImpl.EVENT_NOT_HANDLED;
+        return DISPATCH_NOT_HANDLED;
     }
 
-    /**
-     * @hide
-     */
-    public int dispatchTrackballEvent(Context context, int seq, MotionEvent motion,
-            FinishedEventCallback callback) {
+    // Must be called on the main looper
+    void sendInputEventAndReportResultOnMainLooper(PendingEvent p) {
+        final boolean handled;
         synchronized (mH) {
-            if (DEBUG) Log.d(TAG, "dispatchTrackballEvent");
-
-            if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
-                try {
-                    if (DEBUG) Log.v(TAG, "DISPATCH TRACKBALL: " + mCurMethod);
-                    final long startTime = SystemClock.uptimeMillis();
-                    enqueuePendingEventLocked(startTime, seq, mCurId, callback);
-                    mCurMethod.dispatchTrackballEvent(seq, motion, mInputMethodCallback);
-                    return ViewRootImpl.EVENT_IN_PROGRESS;
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId + " dropping trackball: " + motion, e);
-                }
+            int result = sendInputEventOnMainLooperLocked(p);
+            if (result == DISPATCH_IN_PROGRESS) {
+                return;
             }
+
+            handled = (result == DISPATCH_HANDLED);
         }
-        return ViewRootImpl.EVENT_NOT_HANDLED;
+
+        invokeFinishedInputEventCallback(p, handled);
     }
 
-    /**
-     * @hide
-     */
-    public int dispatchGenericMotionEvent(Context context, int seq, MotionEvent motion,
-            FinishedEventCallback callback) {
-        synchronized (mH) {
-            if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent");
-
-            if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
-                try {
-                    if (DEBUG) Log.v(TAG, "DISPATCH GENERIC MOTION: " + mCurMethod);
-                    final long startTime = SystemClock.uptimeMillis();
-                    enqueuePendingEventLocked(startTime, seq, mCurId, callback);
-                    mCurMethod.dispatchGenericMotionEvent(seq, motion, mInputMethodCallback);
-                    return ViewRootImpl.EVENT_IN_PROGRESS;
-                } catch (RemoteException e) {
-                    Log.w(TAG, "IME died: " + mCurId + " dropping generic motion: " + motion, e);
-                }
+    // Must be called on the main looper
+    int sendInputEventOnMainLooperLocked(PendingEvent p) {
+        if (mCurChannel != null) {
+            if (mCurSender == null) {
+                mCurSender = new ImeInputEventSender(mCurChannel, mH.getLooper());
             }
+
+            final InputEvent event = p.mEvent;
+            final int seq = event.getSequenceNumber();
+            if (mCurSender.sendInputEvent(seq, event)) {
+                mPendingEvents.put(seq, p);
+                Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
+                        mPendingEvents.size());
+
+                Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p);
+                msg.setAsynchronous(true);
+                mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
+                return DISPATCH_IN_PROGRESS;
+            }
+
+            Log.w(TAG, "Unable to send input event to IME: "
+                    + mCurId + " dropping: " + event);
         }
-        return ViewRootImpl.EVENT_NOT_HANDLED;
+        return DISPATCH_NOT_HANDLED;
     }
 
-    void finishedEvent(int seq, boolean handled) {
-        final FinishedEventCallback callback;
+    void finishedInputEvent(int seq, boolean handled, boolean timeout) {
+        final PendingEvent p;
         synchronized (mH) {
-            PendingEvent p = dequeuePendingEventLocked(seq);
-            if (p == null) {
+            int index = mPendingEvents.indexOfKey(seq);
+            if (index < 0) {
                 return; // spurious, event already finished or timed out
             }
-            mH.removeMessages(MSG_EVENT_TIMEOUT, p);
-            callback = p.mCallback;
-            recyclePendingEventLocked(p);
-        }
-        callback.finishedEvent(seq, handled);
-    }
 
-    void timeoutEvent(int seq) {
-        final FinishedEventCallback callback;
-        synchronized (mH) {
-            PendingEvent p = dequeuePendingEventLocked(seq);
-            if (p == null) {
-                return; // spurious, event already finished or timed out
+            p = mPendingEvents.valueAt(index);
+            mPendingEvents.removeAt(index);
+            Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER, mPendingEvents.size());
+
+            if (timeout) {
+                Log.w(TAG, "Timeout waiting for IME to handle input event after "
+                        + INPUT_METHOD_NOT_RESPONDING_TIMEOUT + " ms: " + p.mInputMethodId);
+            } else {
+                mH.removeMessages(MSG_TIMEOUT_INPUT_EVENT, p);
             }
-            long delay = SystemClock.uptimeMillis() - p.mStartTime;
-            Log.w(TAG, "Timeout waiting for IME to handle input event after "
-                    + delay + "ms: " + p.mInputMethodId);
-            callback = p.mCallback;
-            recyclePendingEventLocked(p);
         }
-        callback.finishedEvent(seq, false);
+
+        invokeFinishedInputEventCallback(p, handled);
     }
 
-    private void enqueuePendingEventLocked(
-            long startTime, int seq, String inputMethodId, FinishedEventCallback callback) {
-        PendingEvent p = obtainPendingEventLocked(startTime, seq, inputMethodId, callback);
-        p.mNext = mFirstPendingEvent;
-        mFirstPendingEvent = p;
-
-        Message msg = mH.obtainMessage(MSG_EVENT_TIMEOUT, seq, 0, p);
-        msg.setAsynchronous(true);
-        mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
+    // Assumes the event has already been removed from the queue.
+    void invokeFinishedInputEventCallback(PendingEvent p, boolean handled) {
+        p.mHandled = handled;
+        if (p.mHandler.getLooper().isCurrentThread()) {
+            // Already running on the callback handler thread so we can send the
+            // callback immediately.
+            p.run();
+        } else {
+            // Post the event to the callback handler thread.
+            // In this case, the callback will be responsible for recycling the event.
+            Message msg = Message.obtain(p.mHandler, p);
+            msg.setAsynchronous(true);
+            msg.sendToTarget();
+        }
     }
 
-    private PendingEvent dequeuePendingEventLocked(int seq) {
-        PendingEvent p = mFirstPendingEvent;
+    private void flushPendingEventsLocked() {
+        mH.removeMessages(MSG_FLUSH_INPUT_EVENT);
+
+        final int count = mPendingEvents.size();
+        for (int i = 0; i < count; i++) {
+            int seq = mPendingEvents.keyAt(i);
+            Message msg = mH.obtainMessage(MSG_FLUSH_INPUT_EVENT, seq, 0);
+            msg.setAsynchronous(true);
+            msg.sendToTarget();
+        }
+    }
+
+    private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
+            String inputMethodId, FinishedInputEventCallback callback, Handler handler) {
+        PendingEvent p = mPendingEventPool.acquire();
         if (p == null) {
-            return null;
-        }
-        if (p.mSeq == seq) {
-            mFirstPendingEvent = p.mNext;
-        } else {
-            PendingEvent prev;
-            do {
-                prev = p;
-                p = p.mNext;
-                if (p == null) {
-                    return null;
-                }
-            } while (p.mSeq != seq);
-            prev.mNext = p.mNext;
-        }
-        p.mNext = null;
-        return p;
-    }
-
-    private PendingEvent obtainPendingEventLocked(
-            long startTime, int seq, String inputMethodId, FinishedEventCallback callback) {
-        PendingEvent p = mPendingEventPool;
-        if (p != null) {
-            mPendingEventPoolSize -= 1;
-            mPendingEventPool = p.mNext;
-            p.mNext = null;
-        } else {
             p = new PendingEvent();
         }
-
-        p.mStartTime = startTime;
-        p.mSeq = seq;
+        p.mEvent = event;
+        p.mToken = token;
         p.mInputMethodId = inputMethodId;
         p.mCallback = callback;
+        p.mHandler = handler;
         return p;
     }
 
     private void recyclePendingEventLocked(PendingEvent p) {
-        p.mInputMethodId = null;
-        p.mCallback = null;
-
-        if (mPendingEventPoolSize < MAX_PENDING_EVENT_POOL_SIZE) {
-            mPendingEventPoolSize += 1;
-            p.mNext = mPendingEventPool;
-            mPendingEventPool = p;
-        }
+        p.recycle();
+        mPendingEventPool.release(p);
     }
 
     public void showInputMethodPicker() {
@@ -1938,16 +1945,45 @@
      * the IME has been finished.
      * @hide
      */
-    public interface FinishedEventCallback {
-        public void finishedEvent(int seq, boolean handled);
+    public interface FinishedInputEventCallback {
+        public void onFinishedInputEvent(Object token, boolean handled);
     }
 
-    private static final class PendingEvent {
-        public PendingEvent mNext;
+    private final class ImeInputEventSender extends InputEventSender {
+        public ImeInputEventSender(InputChannel inputChannel, Looper looper) {
+            super(inputChannel, looper);
+        }
 
-        public long mStartTime;
-        public int mSeq;
+        @Override
+        public void onInputEventFinished(int seq, boolean handled) {
+            finishedInputEvent(seq, handled, false);
+        }
+    }
+
+    private final class PendingEvent implements Runnable {
+        public InputEvent mEvent;
+        public Object mToken;
         public String mInputMethodId;
-        public FinishedEventCallback mCallback;
+        public FinishedInputEventCallback mCallback;
+        public Handler mHandler;
+        public boolean mHandled;
+
+        public void recycle() {
+            mEvent = null;
+            mToken = null;
+            mInputMethodId = null;
+            mCallback = null;
+            mHandler = null;
+            mHandled = false;
+        }
+
+        @Override
+        public void run() {
+            mCallback.onFinishedInputEvent(mToken, mHandled);
+
+            synchronized (mH) {
+                recyclePendingEventLocked(this);
+            }
+        }
     }
 }
diff --git a/core/java/android/webkit/AccessibilityInjectorFallback.java b/core/java/android/webkit/AccessibilityInjectorFallback.java
index 6417527..40cc4e9 100644
--- a/core/java/android/webkit/AccessibilityInjectorFallback.java
+++ b/core/java/android/webkit/AccessibilityInjectorFallback.java
@@ -438,7 +438,6 @@
             event.setFromIndex(0);
             event.setToIndex(selection.length());
             sendAccessibilityEvent(event);
-            event.recycle();
         }
     }
 
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 24ac54f..33e8364 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -70,6 +70,7 @@
      * request's LoadListener
      */
     private final static int MAX_OUTSTANDING_REQUESTS = 300;
+    private final static String SCHEME_HOST_DELIMITER = "://";
 
     private final CallbackProxy mCallbackProxy;
     private final WebSettingsClassic mSettings;
@@ -498,9 +499,14 @@
                             .getCurrentItem();
                     if (item != null) {
                         WebAddress uri = new WebAddress(item.getUrl());
-                        String schemePlusHost = uri.getScheme() + uri.getHost();
+                        String schemePlusHost = uri.getScheme() + SCHEME_HOST_DELIMITER +
+                                uri.getHost();
                         String[] up = mDatabase.getUsernamePassword(
                                 schemePlusHost);
+                        if (up == null) { // no row found, try again using the legacy method
+                            schemePlusHost = uri.getScheme() + uri.getHost();
+                            up = mDatabase.getUsernamePassword(schemePlusHost);
+                        }
                         if (up != null && up[0] != null) {
                             setUsernamePassword(up[0], up[1]);
                         }
@@ -815,7 +821,7 @@
             }
             WebAddress uri = new WebAddress(mCallbackProxy
                     .getBackForwardList().getCurrentItem().getUrl());
-            String schemePlusHost = uri.getScheme() + uri.getHost();
+            String schemePlusHost = uri.getScheme() + SCHEME_HOST_DELIMITER + uri.getHost();
             // Check to see if the username & password appear in
             // the post data (there could be another form on the
             // page and that was posted instead.
diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java
index 684ec07..17eb2df 100644
--- a/core/java/android/webkit/HTML5Audio.java
+++ b/core/java/android/webkit/HTML5Audio.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.media.AudioManager;
 import android.media.MediaPlayer;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -84,6 +85,7 @@
     // See http://www.whatwg.org/specs/web-apps/current-work/#event-media-timeupdate
     private Timer mTimer;
     private final class TimeupdateTask extends TimerTask {
+        @Override
         public void run() {
             HTML5Audio.this.obtainMessage(TIMEUPDATE).sendToTarget();
         }
@@ -139,11 +141,13 @@
     // (i.e. the webviewcore thread here)
 
     // MediaPlayer.OnBufferingUpdateListener
+    @Override
     public void onBufferingUpdate(MediaPlayer mp, int percent) {
         nativeOnBuffering(percent, mNativePointer);
     }
 
     // MediaPlayer.OnCompletionListener;
+    @Override
     public void onCompletion(MediaPlayer mp) {
         mState = COMPLETE;
         mProcessingOnEnd = true;
@@ -156,6 +160,7 @@
     }
 
     // MediaPlayer.OnErrorListener
+    @Override
     public boolean onError(MediaPlayer mp, int what, int extra) {
         mState = ERROR;
         resetMediaPlayer();
@@ -164,6 +169,7 @@
     }
 
     // MediaPlayer.OnPreparedListener
+    @Override
     public void onPrepared(MediaPlayer mp) {
         mState = PREPARED;
         if (mTimer != null) {
@@ -178,6 +184,7 @@
     }
 
     // MediaPlayer.OnSeekCompleteListener
+    @Override
     public void onSeekComplete(MediaPlayer mp) {
         nativeOnTimeupdate(mp.getCurrentPosition(), mNativePointer);
     }
@@ -231,7 +238,7 @@
                 headers.put(HIDE_URL_LOGS, "true");
             }
 
-            mMediaPlayer.setDataSource(url, headers);
+            mMediaPlayer.setDataSource(mContext, Uri.parse(url), headers);
             mState = INITIALIZED;
             mMediaPlayer.prepareAsync();
         } catch (IOException e) {
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index d901d0a..8ae0021 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1004,6 +1004,7 @@
      * @param flag true if plugins should be enabled
      * @deprecated This method has been deprecated in favor of
      *             {@link #setPluginState}
+     * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
      */
     @Deprecated
     public synchronized void setPluginsEnabled(boolean flag) {
@@ -1032,6 +1033,7 @@
      * @param pluginsPath a String path to the directory containing plugins
      * @deprecated This method is no longer used as plugins are loaded from
      *             their own APK via the system's package manager.
+     * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
      */
     @Deprecated
     public synchronized void setPluginsPath(String pluginsPath) {
@@ -1224,6 +1226,7 @@
      * @return true if plugins are enabled
      * @see #setPluginsEnabled
      * @deprecated This method has been replaced by {@link #getPluginState}
+     * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
      */
     @Deprecated
     public synchronized boolean getPluginsEnabled() {
@@ -1249,6 +1252,7 @@
      * @return an empty string
      * @deprecated This method is no longer used as plugins are loaded from
      * their own APK via the system's package manager.
+     * @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
      */
     @Deprecated
     public synchronized String getPluginsPath() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index aa9a329..1f00c9c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -573,7 +573,8 @@
      * forms. Note that this is unrelated to the credentials used for HTTP
      * authentication.
      *
-     * @param host the host that required the credentials
+     * @param host the host that required the credentials. It is recommended that
+     *             the host is given using scheme://hostname format.
      * @param username the username for the given host
      * @param password the password for the given host
      * @see WebViewDatabase#clearUsernamePassword
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 67041ac..c7dacf3 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -5419,7 +5419,7 @@
         ClipData clipData = cm.getPrimaryClip();
         if (clipData != null) {
             ClipData.Item clipItem = clipData.getItemAt(0);
-            CharSequence pasteText = clipItem.getText();
+            CharSequence pasteText = clipItem.coerceToText(mContext);
             if (mInputConnection != null) {
                 mInputConnection.replaceSelection(pasteText);
             }
diff --git a/core/java/android/webkit/WebViewDatabaseClassic.java b/core/java/android/webkit/WebViewDatabaseClassic.java
index be01028..5ad4fa5 100644
--- a/core/java/android/webkit/WebViewDatabaseClassic.java
+++ b/core/java/android/webkit/WebViewDatabaseClassic.java
@@ -37,7 +37,7 @@
     private static final String DATABASE_FILE = "webview.db";
     private static final String CACHE_DATABASE_FILE = "webviewCache.db";
 
-    private static final int DATABASE_VERSION = 11;
+    private static final int DATABASE_VERSION = 12;
     // 2 -> 3 Modified Cache table to allow cache of redirects
     // 3 -> 4 Added Oma-Downloads table
     // 4 -> 5 Modified Cache table to support persistent contentLength
@@ -50,6 +50,7 @@
     // 10 -> 11 Drop cookies and cache now managed by the chromium stack,
     //          and update the form data table to use the new format
     //          implemented for b/5265606.
+    // 11 -> 12 Add a delimiter between scheme and host when storing passwords
 
     private static WebViewDatabaseClassic sInstance = null;
     private static final Object sInstanceLock = new Object();
@@ -169,11 +170,23 @@
     private static void upgradeDatabase() {
         upgradeDatabaseToV10();
         upgradeDatabaseFromV10ToV11();
+        upgradeDatabaseFromV11ToV12();
         // Add future database upgrade functions here, one version at a
         // time.
         sDatabase.setVersion(DATABASE_VERSION);
     }
 
+    private static void upgradeDatabaseFromV11ToV12() {
+        int oldVersion = sDatabase.getVersion();
+
+        if (oldVersion >= 12) {
+            // Nothing to do.
+            return;
+        }
+        // delete the rows in the database.
+        sDatabase.delete(mTableNames[TABLE_PASSWORD_ID], null, null);
+    }
+
     private static void upgradeDatabaseFromV10ToV11() {
         int oldVersion = sDatabase.getVersion();
 
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 18df0b1..00d87bd 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -25,8 +25,13 @@
 
 /**
  * Top level factory, used creating all the main WebView implementation classes.
+ *
+ * @hide
  */
-class WebViewFactory {
+public final class WebViewFactory {
+    public static final String WEBVIEW_EXPERIMENTAL_PROPERTY = "persist.sys.webview.exp";
+    private static final String DEPRECATED_CHROMIUM_PROPERTY = "webview.use_chromium";
+
     // Default Provider factory class name.
     // TODO: When the Chromium powered WebView is ready, it should be the default factory class.
     private static final String DEFAULT_WEBVIEW_FACTORY = "android.webkit.WebViewClassic$Factory";
@@ -43,16 +48,17 @@
     private static WebViewFactoryProvider sProviderInstance;
     private static final Object sProviderLock = new Object();
 
+    public static boolean isExperimentalWebViewAvailable() {
+        return Build.IS_DEBUGGABLE && (new java.io.File(CHROMIUM_WEBVIEW_JAR).exists());
+    }
+
     static WebViewFactoryProvider getProvider() {
         synchronized (sProviderLock) {
             // For now the main purpose of this function (and the factory abstraction) is to keep
             // us honest and minimize usage of WebViewClassic internals when binding the proxy.
             if (sProviderInstance != null) return sProviderInstance;
 
-            // For debug builds, we allow a system property to specify that we should use the
-            // Chromium powered WebView. This enables us to switch between implementations
-            // at runtime. For user (release) builds, don't allow this.
-            if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("webview.use_chromium", false)) {
+            if (isExperimentalWebViewEnabled()) {
                 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
                 try {
                     sProviderInstance = loadChromiumProvider();
@@ -76,6 +82,20 @@
         }
     }
 
+    // For debug builds, we allow a system property to specify that we should use the
+    // experimtanl Chromium powered WebView. This enables us to switch between
+    // implementations at runtime. For user (release) builds, don't allow this.
+    private static boolean isExperimentalWebViewEnabled() {
+        if (!isExperimentalWebViewAvailable())
+            return false;
+        if (SystemProperties.getBoolean(DEPRECATED_CHROMIUM_PROPERTY, false)) {
+            Log.w(LOGTAG, String.format("The property %s has been deprecated. Please use %s.",
+                    DEPRECATED_CHROMIUM_PROPERTY, WEBVIEW_EXPERIMENTAL_PROPERTY));
+            return true;
+        }
+        return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY, false);
+    }
+
     // TODO: This allows us to have the legacy and Chromium WebView coexist for development
     // and side-by-side testing. After transition, remove this when no longer required.
     private static WebViewFactoryProvider loadChromiumProvider() {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 396fd68..94dadb4 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2606,7 +2606,7 @@
             mGlobalLayoutListenerAddedFilter = false;
         }
 
-        if (mAdapter != null) {
+        if (mAdapter != null && mDataSetObserver != null) {
             mAdapter.unregisterDataSetObserver(mDataSetObserver);
             mDataSetObserver = null;
         }
@@ -6167,6 +6167,7 @@
         private ArrayList<View> mSkippedScrap;
 
         private SparseArray<View> mTransientStateViews;
+        private LongSparseArray<View> mTransientStateViewsById;
 
         public void setViewTypeCount(int viewTypeCount) {
             if (viewTypeCount < 1) {
@@ -6205,6 +6206,12 @@
                     mTransientStateViews.valueAt(i).forceLayout();
                 }
             }
+            if (mTransientStateViewsById != null) {
+                final int count = mTransientStateViewsById.size();
+                for (int i = 0; i < count; i++) {
+                    mTransientStateViewsById.valueAt(i).forceLayout();
+                }
+            }
         }
 
         public boolean shouldRecycleViewType(int viewType) {
@@ -6234,6 +6241,9 @@
             if (mTransientStateViews != null) {
                 mTransientStateViews.clear();
             }
+            if (mTransientStateViewsById != null) {
+                mTransientStateViewsById.clear();
+            }
         }
 
         /**
@@ -6281,16 +6291,21 @@
         }
 
         View getTransientStateView(int position) {
-            if (mTransientStateViews == null) {
-                return null;
+            if (mAdapter != null && mAdapterHasStableIds && mTransientStateViewsById != null) {
+                long id = mAdapter.getItemId(position);
+                View result = mTransientStateViewsById.get(id);
+                mTransientStateViewsById.remove(id);
+                return result;
             }
-            final int index = mTransientStateViews.indexOfKey(position);
-            if (index < 0) {
-                return null;
+            if (mTransientStateViews != null) {
+                final int index = mTransientStateViews.indexOfKey(position);
+                if (index >= 0) {
+                    View result = mTransientStateViews.valueAt(index);
+                    mTransientStateViews.removeAt(index);
+                    return result;
+                }
             }
-            final View result = mTransientStateViews.valueAt(index);
-            mTransientStateViews.removeAt(index);
-            return result;
+            return null;
         }
 
         /**
@@ -6300,6 +6315,9 @@
             if (mTransientStateViews != null) {
                 mTransientStateViews.clear();
             }
+            if (mTransientStateViewsById != null) {
+                mTransientStateViewsById.clear();
+            }
         }
 
         /**
@@ -6342,11 +6360,20 @@
                     mSkippedScrap.add(scrap);
                 }
                 if (scrapHasTransientState) {
-                    if (mTransientStateViews == null) {
-                        mTransientStateViews = new SparseArray<View>();
-                    }
                     scrap.dispatchStartTemporaryDetach();
-                    mTransientStateViews.put(position, scrap);
+                    if (mAdapter != null && mAdapterHasStableIds) {
+                        if (mTransientStateViewsById == null) {
+                            mTransientStateViewsById = new LongSparseArray<View>();
+                        }
+                        mTransientStateViewsById.put(lp.itemId, scrap);
+                    } else if (!mDataChanged) {
+                        // avoid putting views on transient state list during a data change;
+                        // the layout positions may be out of sync with the adapter positions
+                        if (mTransientStateViews == null) {
+                            mTransientStateViews = new SparseArray<View>();
+                        }
+                        mTransientStateViews.put(position, scrap);
+                    }
                 }
                 return;
             }
@@ -6405,10 +6432,18 @@
                             removeDetachedView(victim, false);
                         }
                         if (scrapHasTransientState) {
-                            if (mTransientStateViews == null) {
-                                mTransientStateViews = new SparseArray<View>();
+                            if (mAdapter != null && mAdapterHasStableIds) {
+                                if (mTransientStateViewsById == null) {
+                                    mTransientStateViewsById = new LongSparseArray<View>();
+                                }
+                                long id = mAdapter.getItemId(mFirstActivePosition + i);
+                                mTransientStateViewsById.put(id, victim);
+                            } else {
+                                if (mTransientStateViews == null) {
+                                    mTransientStateViews = new SparseArray<View>();
+                                }
+                                mTransientStateViews.put(mFirstActivePosition + i, victim);
                             }
-                            mTransientStateViews.put(mFirstActivePosition + i, victim);
                         }
                         continue;
                     }
@@ -6457,6 +6492,15 @@
                     }
                 }
             }
+            if (mTransientStateViewsById != null) {
+                for (int i = 0; i < mTransientStateViewsById.size(); i++) {
+                    final View v = mTransientStateViewsById.valueAt(i);
+                    if (!v.hasTransientState()) {
+                        mTransientStateViewsById.removeAt(i);
+                        i--;
+                    }
+                }
+            }
         }
 
         /**
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 06dadb0..34cfea5 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -20,6 +20,7 @@
 
 import android.app.AlertDialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -66,20 +67,18 @@
 
     private final static String TAG = "AppSecurityPermissions";
     private final static boolean localLOGV = false;
-    private Context mContext;
-    private LayoutInflater mInflater;
-    private PackageManager mPm;
-    private PackageInfo mInstalledPackageInfo;
+    private final Context mContext;
+    private final LayoutInflater mInflater;
+    private final PackageManager mPm;
     private final Map<String, MyPermissionGroupInfo> mPermGroups
             = new HashMap<String, MyPermissionGroupInfo>();
     private final List<MyPermissionGroupInfo> mPermGroupsList
             = new ArrayList<MyPermissionGroupInfo>();
-    private final PermissionGroupInfoComparator mPermGroupComparator;
-    private final PermissionInfoComparator mPermComparator;
-    private List<MyPermissionInfo> mPermsList;
-    private CharSequence mNewPermPrefix;
-    private Drawable mNormalIcon;
-    private Drawable mDangerousIcon;
+    private final PermissionGroupInfoComparator mPermGroupComparator = new PermissionGroupInfoComparator();
+    private final PermissionInfoComparator mPermComparator = new PermissionInfoComparator();
+    private final List<MyPermissionInfo> mPermsList = new ArrayList<MyPermissionInfo>();
+    private final CharSequence mNewPermPrefix;
+    private String mPackageName;
 
     static class MyPermissionGroupInfo extends PermissionGroupInfo {
         CharSequence mLabel;
@@ -113,7 +112,7 @@
         }
     }
 
-    static class MyPermissionInfo extends PermissionInfo {
+    private static class MyPermissionInfo extends PermissionInfo {
         CharSequence mLabel;
 
         /**
@@ -132,25 +131,17 @@
          */
         boolean mNew;
 
-        MyPermissionInfo() {
-        }
-
         MyPermissionInfo(PermissionInfo info) {
             super(info);
         }
-
-        MyPermissionInfo(MyPermissionInfo info) {
-            super(info);
-            mNewReqFlags = info.mNewReqFlags;
-            mExistingReqFlags = info.mExistingReqFlags;
-            mNew = info.mNew;
-        }
     }
 
     public static class PermissionItemView extends LinearLayout implements View.OnClickListener {
         MyPermissionGroupInfo mGroup;
         MyPermissionInfo mPerm;
         AlertDialog mDialog;
+        private boolean mShowRevokeUI = false;
+        private String mPackageName;
 
         public PermissionItemView(Context context, AttributeSet attrs) {
             super(context, attrs);
@@ -158,9 +149,12 @@
         }
 
         public void setPermission(MyPermissionGroupInfo grp, MyPermissionInfo perm,
-                boolean first, CharSequence newPermPrefix) {
+                boolean first, CharSequence newPermPrefix, String packageName,
+                boolean showRevokeUI) {
             mGroup = grp;
             mPerm = perm;
+            mShowRevokeUI = showRevokeUI;
+            mPackageName = packageName;
 
             ImageView permGrpIcon = (ImageView) findViewById(R.id.perm_icon);
             TextView permNameView = (TextView) findViewById(R.id.perm_name);
@@ -219,6 +213,7 @@
                 }
                 builder.setCancelable(true);
                 builder.setIcon(mGroup.loadGroupIcon(pm));
+                addRevokeUIIfNecessary(builder);
                 mDialog = builder.show();
                 mDialog.setCanceledOnTouchOutside(true);
             }
@@ -231,27 +226,43 @@
                 mDialog.dismiss();
             }
         }
+
+        private void addRevokeUIIfNecessary(AlertDialog.Builder builder) {
+            if (!mShowRevokeUI) {
+                return;
+            }
+
+            final boolean isRequired =
+                    ((mPerm.mExistingReqFlags & PackageInfo.REQUESTED_PERMISSION_REQUIRED) != 0);
+
+            if (isRequired) {
+                return;
+            }
+
+            DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    PackageManager pm = getContext().getPackageManager();
+                    pm.revokePermission(mPackageName, mPerm.name);
+                    PermissionItemView.this.setVisibility(View.GONE);
+                }
+            };
+            builder.setNegativeButton(R.string.revoke, ocl);
+            builder.setPositiveButton(R.string.ok, null);
+        }
     }
 
-    public AppSecurityPermissions(Context context, List<PermissionInfo> permList) {
+    private AppSecurityPermissions(Context context) {
         mContext = context;
+        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mPm = mContext.getPackageManager();
-        loadResources();
-        mPermComparator = new PermissionInfoComparator();
-        mPermGroupComparator = new PermissionGroupInfoComparator();
-        for (PermissionInfo pi : permList) {
-            mPermsList.add(new MyPermissionInfo(pi));
-        }
-        setPermissions(mPermsList);
+        // Pick up from framework resources instead.
+        mNewPermPrefix = mContext.getText(R.string.perms_new_perm_prefix);
     }
-    
+
     public AppSecurityPermissions(Context context, String packageName) {
-        mContext = context;
-        mPm = mContext.getPackageManager();
-        loadResources();
-        mPermComparator = new PermissionInfoComparator();
-        mPermGroupComparator = new PermissionGroupInfoComparator();
-        mPermsList = new ArrayList<MyPermissionInfo>();
+        this(context);
+        mPackageName = packageName;
         Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>();
         PackageInfo pkgInfo;
         try {
@@ -264,23 +275,17 @@
         if((pkgInfo.applicationInfo != null) && (pkgInfo.applicationInfo.uid != -1)) {
             getAllUsedPermissions(pkgInfo.applicationInfo.uid, permSet);
         }
-        for(MyPermissionInfo tmpInfo : permSet) {
-            mPermsList.add(tmpInfo);
-        }
+        mPermsList.addAll(permSet);
         setPermissions(mPermsList);
     }
 
     public AppSecurityPermissions(Context context, PackageInfo info) {
-        mContext = context;
-        mPm = mContext.getPackageManager();
-        loadResources();
-        mPermComparator = new PermissionInfoComparator();
-        mPermGroupComparator = new PermissionGroupInfoComparator();
-        mPermsList = new ArrayList<MyPermissionInfo>();
+        this(context);
         Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>();
         if(info == null) {
             return;
         }
+        mPackageName = info.packageName;
 
         // Convert to a PackageInfo
         PackageInfo installedPkgInfo = null;
@@ -300,23 +305,14 @@
                 sharedUid = mPm.getUidForSharedUser(info.sharedUserId);
                 getAllUsedPermissions(sharedUid, permSet);
             } catch (NameNotFoundException e) {
-                Log.w(TAG, "Could'nt retrieve shared user id for:"+info.packageName);
+                Log.w(TAG, "Couldn't retrieve shared user id for: " + info.packageName);
             }
         }
         // Retrieve list of permissions
-        for (MyPermissionInfo tmpInfo : permSet) {
-            mPermsList.add(tmpInfo);
-        }
+        mPermsList.addAll(permSet);
         setPermissions(mPermsList);
     }
 
-    private void loadResources() {
-        // Pick up from framework resources instead.
-        mNewPermPrefix = mContext.getText(R.string.perms_new_perm_prefix);
-        mNormalIcon = mContext.getResources().getDrawable(R.drawable.ic_text_dot);
-        mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission);
-    }
-
     /**
      * Utility to retrieve a view displaying a single permission.  This provides
      * the old UI layout for permissions; it is only here for the device admin
@@ -332,10 +328,6 @@
                 description, dangerous, icon);
     }
     
-    public PackageInfo getInstalledPackageInfo() {
-        return mInstalledPackageInfo;
-    }
-
     private void getAllUsedPermissions(int sharedUid, Set<MyPermissionInfo> permSet) {
         String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
         if(sharedPkgList == null || (sharedPkgList.length == 0)) {
@@ -346,17 +338,12 @@
         }
     }
     
-    private void getPermissionsForPackage(String packageName, 
-            Set<MyPermissionInfo> permSet) {
-        PackageInfo pkgInfo;
+    private void getPermissionsForPackage(String packageName, Set<MyPermissionInfo> permSet) {
         try {
-            pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
-        } catch (NameNotFoundException e) {
-            Log.w(TAG, "Couldn't retrieve permissions for package:"+packageName);
-            return;
-        }
-        if ((pkgInfo != null) && (pkgInfo.requestedPermissions != null)) {
+            PackageInfo pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
             extractPerms(pkgInfo, permSet, pkgInfo);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Couldn't retrieve permissions for package: " + packageName);
         }
     }
 
@@ -367,7 +354,6 @@
         if ((strList == null) || (strList.length == 0)) {
             return;
         }
-        mInstalledPackageInfo = installedPkgInfo;
         for (int i=0; i<strList.length; i++) {
             String permName = strList[i];
             // If we are only looking at an existing app, then we only
@@ -467,17 +453,23 @@
     }
 
     public View getPermissionsView() {
-        return getPermissionsView(WHICH_ALL);
+        return getPermissionsView(WHICH_ALL, false);
+    }
+
+    public View getPermissionsViewWithRevokeButtons() {
+        return getPermissionsView(WHICH_ALL, true);
     }
 
     public View getPermissionsView(int which) {
-        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        return getPermissionsView(which, false);
+    }
 
+    private View getPermissionsView(int which, boolean showRevokeUI) {
         LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null);
         LinearLayout displayList = (LinearLayout) permsView.findViewById(R.id.perms_list);
         View noPermsView = permsView.findViewById(R.id.no_permissions);
 
-        displayPermissions(mPermGroupsList, displayList, which);
+        displayPermissions(mPermGroupsList, displayList, which, showRevokeUI);
         if (displayList.getChildCount() <= 0) {
             noPermsView.setVisibility(View.VISIBLE);
         }
@@ -490,7 +482,7 @@
      * list of permission descriptions.
      */
     private void displayPermissions(List<MyPermissionGroupInfo> groups,
-            LinearLayout permListView, int which) {
+            LinearLayout permListView, int which, boolean showRevokeUI) {
         permListView.removeAllViews();
 
         int spacing = (int)(8*mContext.getResources().getDisplayMetrics().density);
@@ -501,7 +493,7 @@
             for (int j=0; j<perms.size(); j++) {
                 MyPermissionInfo perm = perms.get(j);
                 View view = getPermissionItemView(grp, perm, j == 0,
-                        which != WHICH_NEW ? mNewPermPrefix : null);
+                        which != WHICH_NEW ? mNewPermPrefix : null, showRevokeUI);
                 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                         ViewGroup.LayoutParams.MATCH_PARENT,
                         ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -520,18 +512,19 @@
     }
 
     private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp,
-            MyPermissionInfo perm, boolean first, CharSequence newPermPrefix) {
-        return getPermissionItemView(mContext, mInflater, grp, perm, first, newPermPrefix);
+            MyPermissionInfo perm, boolean first, CharSequence newPermPrefix, boolean showRevokeUI) {
+        return getPermissionItemView(mContext, mInflater, grp, perm, first, newPermPrefix,
+                mPackageName, showRevokeUI);
     }
 
     private static PermissionItemView getPermissionItemView(Context context, LayoutInflater inflater,
             MyPermissionGroupInfo grp, MyPermissionInfo perm, boolean first,
-            CharSequence newPermPrefix) {
-        PermissionItemView permView = (PermissionItemView)inflater.inflate(
+            CharSequence newPermPrefix, String packageName, boolean showRevokeUI) {
+            PermissionItemView permView = (PermissionItemView)inflater.inflate(
                 (perm.flags & PermissionInfo.FLAG_COSTS_MONEY) != 0
                         ? R.layout.app_permission_item_money : R.layout.app_permission_item,
                 null);
-        permView.setPermission(grp, perm, first, newPermPrefix);
+        permView.setPermission(grp, perm, first, newPermPrefix, packageName, showRevokeUI);
         return permView;
     }
 
@@ -557,16 +550,27 @@
     private boolean isDisplayablePermission(PermissionInfo pInfo, int newReqFlags,
             int existingReqFlags) {
         final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
-        // Dangerous and normal permissions are always shown to the user.
-        if (base == PermissionInfo.PROTECTION_DANGEROUS ||
-                base == PermissionInfo.PROTECTION_NORMAL) {
+        final boolean isNormal = (base == PermissionInfo.PROTECTION_NORMAL);
+        final boolean isDangerous = (base == PermissionInfo.PROTECTION_DANGEROUS);
+        final boolean isRequired =
+                ((newReqFlags&PackageInfo.REQUESTED_PERMISSION_REQUIRED) != 0);
+        final boolean isDevelopment =
+                ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0);
+        final boolean wasGranted =
+                ((existingReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0);
+        final boolean isGranted =
+                ((newReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0);
+
+        // Dangerous and normal permissions are always shown to the user if the permission
+        // is required, or it was previously granted
+        if ((isNormal || isDangerous) && (isRequired || wasGranted || isGranted)) {
             return true;
         }
+
         // Development permissions are only shown to the user if they are already
         // granted to the app -- if we are installing an app and they are not
         // already granted, they will not be granted as part of the install.
-        if ((existingReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
-                && (pInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+        if (isDevelopment && wasGranted) {
             if (localLOGV) Log.i(TAG, "Special perm " + pInfo.name
                     + ": protlevel=0x" + Integer.toHexString(pInfo.protectionLevel));
             return true;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 07d3a7a..8f515f5 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -419,7 +419,7 @@
      * @see #getCalendarView()
      */
     public boolean getCalendarViewShown() {
-        return mCalendarView.isShown();
+        return (mCalendarView.getVisibility() == View.VISIBLE);
     }
 
     /**
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index c6b6dd6..b6c1e5b 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -39,8 +39,6 @@
     // proportional fonts don't shake rendering
 
     Calendar mCalendar;
-    private final static String m12 = "h:mm:ss aa";
-    private final static String m24 = "k:mm:ss";
     @SuppressWarnings("FieldCanBeLocal") // We must keep a reference to this observer
     private FormatChangeObserver mFormatChangeObserver;
 
@@ -102,19 +100,8 @@
         mTickerStopped = true;
     }
 
-    /**
-     * Pulls 12/24 mode from system settings
-     */
-    private boolean get24HourMode() {
-        return android.text.format.DateFormat.is24HourFormat(getContext());
-    }
-
     private void setFormat() {
-        if (get24HourMode()) {
-            mFormat = m24;
-        } else {
-            mFormat = m12;
-        }
+        mFormat = DateFormat.getTimeFormatString(getContext());
     }
 
     private class FormatChangeObserver extends ContentObserver {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index dc305a5..0aeef63 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -316,7 +316,7 @@
     private void setErrorIcon(Drawable icon) {
         Drawables dr = mTextView.mDrawables;
         if (dr == null) {
-            mTextView.mDrawables = dr = new Drawables();
+            mTextView.mDrawables = dr = new Drawables(mTextView.getContext());
         }
         dr.setErrorDrawable(icon, mTextView);
 
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index a746370..7b81aa8 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -36,6 +36,8 @@
 
 import java.util.ArrayList;
 
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
 /**
  * A view that shows items in a vertically scrolling two-level list. This
  * differs from the {@link ListView} by allowing two levels: groups which can
@@ -76,6 +78,10 @@
  * @attr ref android.R.styleable#ExpandableListView_childIndicatorLeft
  * @attr ref android.R.styleable#ExpandableListView_childIndicatorRight
  * @attr ref android.R.styleable#ExpandableListView_childDivider
+ * @attr ref android.R.styleable#ExpandableListView_indicatorStart
+ * @attr ref android.R.styleable#ExpandableListView_indicatorEnd
+ * @attr ref android.R.styleable#ExpandableListView_childIndicatorStart
+ * @attr ref android.R.styleable#ExpandableListView_childIndicatorEnd
  */
 public class ExpandableListView extends ListView {
 
@@ -134,6 +140,12 @@
     /** Right bound for drawing the indicator. */
     private int mIndicatorRight;
 
+    /** Start bound for drawing the indicator. */
+    private int mIndicatorStart;
+
+    /** End bound for drawing the indicator. */
+    private int mIndicatorEnd;
+
     /**
      * Left bound for drawing the indicator of a child. Value of
      * {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorLeft.
@@ -147,11 +159,28 @@
     private int mChildIndicatorRight;
 
     /**
+     * Start bound for drawing the indicator of a child. Value of
+     * {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorStart.
+     */
+    private int mChildIndicatorStart;
+
+    /**
+     * End bound for drawing the indicator of a child. Value of
+     * {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorEnd.
+     */
+    private int mChildIndicatorEnd;
+
+    /**
      * Denotes when a child indicator should inherit this bound from the generic
      * indicator bounds
      */
     public static final int CHILD_INDICATOR_INHERIT = -1;
-    
+
+    /**
+     * Denotes an undefined value for an indicator
+     */
+    private static final int INDICATOR_UNDEFINED = -2;
+
     /** The indicator drawn next to a group. */
     private Drawable mGroupIndicator;
 
@@ -202,30 +231,118 @@
         super(context, attrs, defStyle);
 
         TypedArray a =
-            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ExpandableListView, defStyle,
-                    0);
+            context.obtainStyledAttributes(attrs,
+                    com.android.internal.R.styleable.ExpandableListView, defStyle, 0);
 
-        mGroupIndicator = a
-                .getDrawable(com.android.internal.R.styleable.ExpandableListView_groupIndicator);
-        mChildIndicator = a
-                .getDrawable(com.android.internal.R.styleable.ExpandableListView_childIndicator);
-        mIndicatorLeft = a
-                .getDimensionPixelSize(com.android.internal.R.styleable.ExpandableListView_indicatorLeft, 0);
-        mIndicatorRight = a
-                .getDimensionPixelSize(com.android.internal.R.styleable.ExpandableListView_indicatorRight, 0);
+        mGroupIndicator = a.getDrawable(
+                com.android.internal.R.styleable.ExpandableListView_groupIndicator);
+        mChildIndicator = a.getDrawable(
+                com.android.internal.R.styleable.ExpandableListView_childIndicator);
+        mIndicatorLeft = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.ExpandableListView_indicatorLeft, 0);
+        mIndicatorRight = a.getDimensionPixelSize(
+                com.android.internal.R.styleable.ExpandableListView_indicatorRight, 0);
         if (mIndicatorRight == 0 && mGroupIndicator != null) {
             mIndicatorRight = mIndicatorLeft + mGroupIndicator.getIntrinsicWidth();
         }
         mChildIndicatorLeft = a.getDimensionPixelSize(
-                com.android.internal.R.styleable.ExpandableListView_childIndicatorLeft, CHILD_INDICATOR_INHERIT);
+                com.android.internal.R.styleable.ExpandableListView_childIndicatorLeft,
+                CHILD_INDICATOR_INHERIT);
         mChildIndicatorRight = a.getDimensionPixelSize(
-                com.android.internal.R.styleable.ExpandableListView_childIndicatorRight, CHILD_INDICATOR_INHERIT);
-        mChildDivider = a.getDrawable(com.android.internal.R.styleable.ExpandableListView_childDivider);
-        
+                com.android.internal.R.styleable.ExpandableListView_childIndicatorRight,
+                CHILD_INDICATOR_INHERIT);
+        mChildDivider = a.getDrawable(
+                com.android.internal.R.styleable.ExpandableListView_childDivider);
+
+        if (!isRtlCompatibilityMode()) {
+            mIndicatorStart = a.getDimensionPixelSize(
+                    com.android.internal.R.styleable.ExpandableListView_indicatorStart,
+                    INDICATOR_UNDEFINED);
+            mIndicatorEnd = a.getDimensionPixelSize(
+                    com.android.internal.R.styleable.ExpandableListView_indicatorEnd,
+                    INDICATOR_UNDEFINED);
+
+            mChildIndicatorStart = a.getDimensionPixelSize(
+                    com.android.internal.R.styleable.ExpandableListView_childIndicatorStart,
+                    CHILD_INDICATOR_INHERIT);
+            mChildIndicatorEnd = a.getDimensionPixelSize(
+                    com.android.internal.R.styleable.ExpandableListView_childIndicatorEnd,
+                    CHILD_INDICATOR_INHERIT);
+        }
+
         a.recycle();
     }
-    
-    
+
+    /**
+     * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or
+     * RTL not supported)
+     */
+    private boolean isRtlCompatibilityMode() {
+        final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+        return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport();
+    }
+
+    /**
+     * Return true if the application tag in the AndroidManifest has set "supportRtl" to true
+     */
+    private boolean hasRtlSupport() {
+        return mContext.getApplicationInfo().hasRtlSupport();
+    }
+
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        resolveIndicator();
+        resolveChildIndicator();
+    }
+
+    /**
+     * Resolve start/end indicator. start/end indicator always takes precedence over left/right
+     * indicator when defined.
+     */
+    private void resolveIndicator() {
+        final boolean isLayoutRtl = isLayoutRtl();
+        if (isLayoutRtl) {
+            if (mIndicatorStart >= 0) {
+                mIndicatorRight = mIndicatorStart;
+            }
+            if (mIndicatorEnd >= 0) {
+                mIndicatorLeft = mIndicatorEnd;
+            }
+        } else {
+            if (mIndicatorStart >= 0) {
+                mIndicatorLeft = mIndicatorStart;
+            }
+            if (mIndicatorEnd >= 0) {
+                mIndicatorRight = mIndicatorEnd;
+            }
+        }
+        if (mIndicatorRight == 0 && mGroupIndicator != null) {
+            mIndicatorRight = mIndicatorLeft + mGroupIndicator.getIntrinsicWidth();
+        }
+    }
+
+    /**
+     * Resolve start/end child indicator. start/end child indicator always takes precedence over
+     * left/right child indicator when defined.
+     */
+    private void resolveChildIndicator() {
+        final boolean isLayoutRtl = isLayoutRtl();
+        if (isLayoutRtl) {
+            if (mChildIndicatorStart >= CHILD_INDICATOR_INHERIT) {
+                mChildIndicatorRight = mChildIndicatorStart;
+            }
+            if (mChildIndicatorEnd >= CHILD_INDICATOR_INHERIT) {
+                mChildIndicatorLeft = mChildIndicatorEnd;
+            }
+        } else {
+            if (mChildIndicatorStart >= CHILD_INDICATOR_INHERIT) {
+                mChildIndicatorLeft = mChildIndicatorStart;
+            }
+            if (mChildIndicatorEnd >= CHILD_INDICATOR_INHERIT) {
+                mChildIndicatorRight = mChildIndicatorEnd;
+            }
+        }
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         // Draw children, etc.
@@ -288,6 +405,9 @@
             // Get more expandable list-related info for this item
             pos = mConnector.getUnflattenedPos(childFlPos);
 
+            final boolean isLayoutRtl = isLayoutRtl();
+            final int width = getWidth();
+
             // If this item type and the previous item type are different, then we need to change
             // the left & right bounds
             if (pos.position.type != lastItemType) {
@@ -300,9 +420,18 @@
                     indicatorRect.left = mIndicatorLeft;
                     indicatorRect.right = mIndicatorRight;
                 }
-                
-                indicatorRect.left += mPaddingLeft;
-                indicatorRect.right += mPaddingLeft;
+
+                if (isLayoutRtl) {
+                    final int temp = indicatorRect.left;
+                    indicatorRect.left = width - indicatorRect.right;
+                    indicatorRect.right = width - temp;
+
+                    indicatorRect.left -= mPaddingRight;
+                    indicatorRect.right -= mPaddingRight;
+                } else {
+                    indicatorRect.left += mPaddingLeft;
+                    indicatorRect.right += mPaddingLeft;
+                }
 
                 lastItemType = pos.position.type; 
             }
@@ -1041,8 +1170,26 @@
     public void setChildIndicatorBounds(int left, int right) {
         mChildIndicatorLeft = left;
         mChildIndicatorRight = right;
+        resolveChildIndicator();
     }
-    
+
+    /**
+     * Sets the relative drawing bounds for the child indicator. For either, you can
+     * specify {@link #CHILD_INDICATOR_INHERIT} to use inherit from the general
+     * indicator's bounds.
+     *
+     * @see #setIndicatorBounds(int, int)
+     * @param start The start position (relative to the start bounds of this View)
+     *            to start drawing the indicator.
+     * @param end The end position (relative to the end bounds of this
+     *            View) to end the drawing of the indicator.
+     */
+    public void setChildIndicatorBoundsRelative(int start, int end) {
+        mChildIndicatorStart = start;
+        mChildIndicatorEnd = end;
+        resolveChildIndicator();
+    }
+
     /**
      * Sets the indicator to be drawn next to a group.
      * 
@@ -1072,8 +1219,26 @@
     public void setIndicatorBounds(int left, int right) {
         mIndicatorLeft = left;
         mIndicatorRight = right;
+        resolveIndicator();
     }
-    
+
+    /**
+     * Sets the relative drawing bounds for the indicators (at minimum, the group indicator
+     * is affected by this; the child indicator is affected by this if the
+     * child indicator bounds are set to inherit).
+     *
+     * @see #setChildIndicatorBounds(int, int)
+     * @param start The start position (relative to the start bounds of this View)
+     *            to start drawing the indicator.
+     * @param end The end position (relative to the end bounds of this
+     *            View) to end the drawing of the indicator.
+     */
+    public void setIndicatorBoundsRelative(int start, int end) {
+        mIndicatorStart = start;
+        mIndicatorEnd = end;
+        resolveIndicator();
+    }
+
     /**
      * Extra menu information specific to an {@link ExpandableListView} provided
      * to the
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 1bbf4eb..cde6ceb 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -204,7 +204,7 @@
 
     @Override
     public boolean hasOverlappingRendering() {
-        return (getBackground() != null);
+        return (getBackground() != null && getBackground().getCurrent() != null);
     }
 
     @Override
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 69e3177..c7914f3 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1550,6 +1550,32 @@
 
             setSelectedPositionInt(mNextSelectedPosition);
 
+            // Remember which child, if any, had accessibility focus. This must
+            // occur before recycling any views, since that will clear
+            // accessibility focus.
+            final ViewRootImpl viewRootImpl = getViewRootImpl();
+            if (viewRootImpl != null) {
+                final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost();
+                if (accessFocusedView != null) {
+                    final View accessFocusedChild = findAccessibilityFocusedChild(
+                            accessFocusedView);
+                    if (accessFocusedChild != null) {
+                        if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) {
+                            // If the views won't be changing, try to maintain
+                            // focus on the current view host and (if
+                            // applicable) its virtual view.
+                            accessibilityFocusLayoutRestoreView = accessFocusedView;
+                            accessibilityFocusLayoutRestoreNode = viewRootImpl
+                                    .getAccessibilityFocusedVirtualView();
+                        } else {
+                            // Otherwise, try to maintain focus at the same
+                            // position.
+                            accessibilityFocusPosition = getPositionForView(accessFocusedChild);
+                        }
+                    }
+                }
+            }
+
             // Pull all children into the RecycleBin.
             // These views will be reused if possible
             final int firstPosition = mFirstPosition;
@@ -1590,30 +1616,6 @@
                 requestFocus();
             }
 
-            // Remember which child, if any, had accessibility focus.
-            final ViewRootImpl viewRootImpl = getViewRootImpl();
-            if (viewRootImpl != null) {
-                final View accessFocusedView = viewRootImpl.getAccessibilityFocusedHost();
-                if (accessFocusedView != null) {
-                    final View accessFocusedChild = findAccessibilityFocusedChild(
-                            accessFocusedView);
-                    if (accessFocusedChild != null) {
-                        if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) {
-                            // If the views won't be changing, try to maintain
-                            // focus on the current view host and (if
-                            // applicable) its virtual view.
-                            accessibilityFocusLayoutRestoreView = accessFocusedView;
-                            accessibilityFocusLayoutRestoreNode = viewRootImpl
-                                    .getAccessibilityFocusedVirtualView();
-                        } else {
-                            // Otherwise, try to maintain focus at the same
-                            // position.
-                            accessibilityFocusPosition = getPositionForView(accessFocusedChild);
-                        }
-                    }
-                }
-            }
-
             // Clear out old views
             detachAllViewsFromParent();
             recycleBin.removeSkippedScrap();
@@ -2415,6 +2417,34 @@
     }
 
     /**
+     * Used by {@link #arrowScrollImpl(int)} to help determine the next selected position
+     * to move to. This can return a position currently not represented by a view on screen
+     * but only in the direction given.
+     *
+     * @param selectedPos Current selected position to move from
+     * @param direction Direction to move in
+     * @return Desired selected position after moving in the given direction
+     */
+    private final int nextSelectedPositionForDirection(int selectedPos, int direction) {
+        int nextSelected;
+        if (direction == View.FOCUS_DOWN) {
+            nextSelected = selectedPos != INVALID_POSITION && selectedPos >= mFirstPosition ?
+                    selectedPos + 1 :
+                    mFirstPosition;
+        } else {
+            final int lastPos = mFirstPosition + getChildCount() - 1;
+            nextSelected = selectedPos != INVALID_POSITION && selectedPos <= lastPos ?
+                    selectedPos - 1 :
+                    lastPos;
+        }
+
+        if (nextSelected < 0 || nextSelected >= mAdapter.getCount()) {
+            return INVALID_POSITION;
+        }
+        return lookForSelectablePosition(nextSelected, direction == View.FOCUS_DOWN);
+    }
+
+    /**
      * Handle an arrow scroll going up or down.  Take into account whether items are selectable,
      * whether there are focusable items etc.
      *
@@ -2429,7 +2459,7 @@
         View selectedView = getSelectedView();
         int selectedPos = mSelectedPosition;
 
-        int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
+        int nextSelectedPosition = nextSelectedPositionForDirection(selectedPos, direction);
         int amountToScroll = amountToScroll(direction, nextSelectedPosition);
 
         // if we are moving focus, we may OVERRIDE the default behavior
@@ -2641,14 +2671,18 @@
         final int listBottom = getHeight() - mListPadding.bottom;
         final int listTop = mListPadding.top;
 
-        final int numChildren = getChildCount();
+        int numChildren = getChildCount();
 
         if (direction == View.FOCUS_DOWN) {
             int indexToMakeVisible = numChildren - 1;
             if (nextSelectedPosition != INVALID_POSITION) {
                 indexToMakeVisible = nextSelectedPosition - mFirstPosition;
             }
-
+            while (numChildren <= indexToMakeVisible) {
+                // Child to view is not attached yet.
+                addViewBelow(getChildAt(numChildren - 1), mFirstPosition + numChildren - 1);
+                numChildren++;
+            }
             final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
             final View viewToMakeVisible = getChildAt(indexToMakeVisible);
 
@@ -2682,6 +2716,12 @@
             if (nextSelectedPosition != INVALID_POSITION) {
                 indexToMakeVisible = nextSelectedPosition - mFirstPosition;
             }
+            while (indexToMakeVisible < 0) {
+                // Child to view is not attached yet.
+                addViewAbove(getChildAt(0), mFirstPosition);
+                mFirstPosition--;
+                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
+            }
             final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
             final View viewToMakeVisible = getChildAt(indexToMakeVisible);
             int goalTop = listTop;
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 5d6ec1e..3df7258 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -41,6 +41,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.RemoteViews.RemoteView;
 
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 import static android.util.Log.d;
 
 /**
@@ -219,28 +220,29 @@
     // with MeasureSpec value overflow and RelativeLayout was one source of them.
     // Some apps came to rely on them. :(
     private boolean mAllowBrokenMeasureSpecs = false;
+    // Compatibility hack. Old versions of the platform would not take
+    // margins and padding into account when generating the height measure spec
+    // for children during the horizontal measure pass.
+    private boolean mMeasureVerticalWithPaddingMargin = false;
 
     // A default width used for RTL measure pass
-    private static int DEFAULT_WIDTH = Integer.MAX_VALUE / 2;
+    private static final int DEFAULT_WIDTH = Integer.MAX_VALUE / 2;
 
     public RelativeLayout(Context context) {
         super(context);
-        mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <=
-                Build.VERSION_CODES.JELLY_BEAN_MR1;
+        queryCompatibilityModes(context);
     }
 
     public RelativeLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
         initFromAttributes(context, attrs);
-        mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <=
-                Build.VERSION_CODES.JELLY_BEAN_MR1;
+        queryCompatibilityModes(context);
     }
 
     public RelativeLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         initFromAttributes(context, attrs);
-        mAllowBrokenMeasureSpecs = context.getApplicationInfo().targetSdkVersion <=
-                Build.VERSION_CODES.JELLY_BEAN_MR1;
+        queryCompatibilityModes(context);
     }
 
     private void initFromAttributes(Context context, AttributeSet attrs) {
@@ -250,6 +252,12 @@
         a.recycle();
     }
 
+    private void queryCompatibilityModes(Context context) {
+        int version = context.getApplicationInfo().targetSdkVersion;
+        mAllowBrokenMeasureSpecs = version <= Build.VERSION_CODES.JELLY_BEAN_MR1;
+        mMeasureVerticalWithPaddingMargin = version >= Build.VERSION_CODES.JELLY_BEAN_MR2;
+    }
+
     @Override
     public boolean shouldDelayChildPressedState() {
         return false;
@@ -691,6 +699,11 @@
                 params.leftMargin, params.rightMargin,
                 mPaddingLeft, mPaddingRight,
                 myWidth);
+        int maxHeight = myHeight;
+        if (mMeasureVerticalWithPaddingMargin) {
+            maxHeight = Math.max(0, myHeight - mPaddingTop - mPaddingBottom -
+                    params.topMargin - params.bottomMargin);
+        }
         int childHeightMeasureSpec;
         if (myHeight < 0 && !mAllowBrokenMeasureSpecs) {
             if (params.height >= 0) {
@@ -703,9 +716,9 @@
                 childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
             }
         } else if (params.width == LayoutParams.MATCH_PARENT) {
-            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.EXACTLY);
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
         } else {
-            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(myHeight, MeasureSpec.AT_MOST);
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);
         }
         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     }
@@ -1211,10 +1224,11 @@
 
         private int mLeft, mTop, mRight, mBottom;
 
-        private int mStart = DEFAULT_RELATIVE;
-        private int mEnd = DEFAULT_RELATIVE;
+        private int mStart = DEFAULT_MARGIN_RELATIVE;
+        private int mEnd = DEFAULT_MARGIN_RELATIVE;
 
         private boolean mRulesChanged = false;
+        private boolean mIsRtlCompatibilityMode = false;
 
         /**
          * When true, uses the parent as the anchor if the anchor doesn't exist or if
@@ -1229,6 +1243,10 @@
             TypedArray a = c.obtainStyledAttributes(attrs,
                     com.android.internal.R.styleable.RelativeLayout_Layout);
 
+            final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
+            mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 ||
+                    !c.getApplicationInfo().hasRtlSupport());
+
             final int[] rules = mRules;
             //noinspection MismatchedReadAndWriteOfArray
             final int[] initialRules = mInitialRules;
@@ -1308,7 +1326,7 @@
                         break;
                 }
             }
-
+            mRulesChanged = true;
             System.arraycopy(rules, LEFT_OF, initialRules, LEFT_OF, VERB_COUNT);
 
             a.recycle();
@@ -1397,28 +1415,132 @@
                     mInitialRules[ALIGN_PARENT_START] != 0 || mInitialRules[ALIGN_PARENT_END] != 0);
         }
 
+        // The way we are resolving rules depends on the layout direction and if we are pre JB MR1
+        // or not.
+        //
+        // If we are pre JB MR1 (said as "RTL compatibility mode"), "left"/"right" rules are having
+        // predominance over any "start/end" rules that could have been defined. A special case:
+        // if no "left"/"right" rule has been defined and "start"/"end" rules are defined then we
+        // resolve those "start"/"end" rules to "left"/"right" respectively.
+        //
+        // If we are JB MR1+, then "start"/"end" rules are having predominance over "left"/"right"
+        // rules. If no "start"/"end" rule is defined then we use "left"/"right" rules.
+        //
+        // In all cases, the result of the resolution should clear the "start"/"end" rules to leave
+        // only the "left"/"right" rules at the end.
         private void resolveRules(int layoutDirection) {
             final boolean isLayoutRtl = (layoutDirection == View.LAYOUT_DIRECTION_RTL);
+
             // Reset to initial state
             System.arraycopy(mInitialRules, LEFT_OF, mRules, LEFT_OF, VERB_COUNT);
-            // Apply rules depending on direction
-            if (mRules[ALIGN_START] != 0) {
-                mRules[isLayoutRtl ? ALIGN_RIGHT : ALIGN_LEFT] = mRules[ALIGN_START];
-            }
-            if (mRules[ALIGN_END] != 0) {
-                mRules[isLayoutRtl ? ALIGN_LEFT : ALIGN_RIGHT] = mRules[ALIGN_END];
-            }
-            if (mRules[START_OF] != 0) {
-                mRules[isLayoutRtl ? RIGHT_OF : LEFT_OF] = mRules[START_OF];
-            }
-            if (mRules[END_OF] != 0) {
-                mRules[isLayoutRtl ? LEFT_OF : RIGHT_OF] = mRules[END_OF];
-            }
-            if (mRules[ALIGN_PARENT_START] != 0) {
-                mRules[isLayoutRtl ? ALIGN_PARENT_RIGHT : ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
-            }
-            if (mRules[ALIGN_PARENT_END] != 0) {
-                mRules[isLayoutRtl ? ALIGN_PARENT_LEFT : ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
+
+            // Apply rules depending on direction and if we are in RTL compatibility mode
+            if (mIsRtlCompatibilityMode) {
+                if (mRules[ALIGN_START] != 0) {
+                    if (mRules[ALIGN_LEFT] == 0) {
+                        // "left" rule is not defined but "start" rule is: use the "start" rule as
+                        // the "left" rule
+                        mRules[ALIGN_LEFT] = mRules[ALIGN_START];
+                    }
+                    mRules[ALIGN_START] = 0;
+                }
+
+                if (mRules[ALIGN_END] != 0) {
+                    if (mRules[ALIGN_RIGHT] == 0) {
+                        // "right" rule is not defined but "end" rule is: use the "end" rule as the
+                        // "right" rule
+                        mRules[ALIGN_RIGHT] = mRules[ALIGN_END];
+                    }
+                    mRules[ALIGN_END] = 0;
+                }
+
+                if (mRules[START_OF] != 0) {
+                    if (mRules[LEFT_OF] == 0) {
+                        // "left" rule is not defined but "start" rule is: use the "start" rule as
+                        // the "left" rule
+                        mRules[LEFT_OF] = mRules[START_OF];
+                    }
+                    mRules[START_OF] = 0;
+                }
+
+                if (mRules[END_OF] != 0) {
+                    if (mRules[RIGHT_OF] == 0) {
+                        // "right" rule is not defined but "end" rule is: use the "end" rule as the
+                        // "right" rule
+                        mRules[RIGHT_OF] = mRules[END_OF];
+                    }
+                    mRules[END_OF] = 0;
+                }
+
+                if (mRules[ALIGN_PARENT_START] != 0) {
+                    if (mRules[ALIGN_PARENT_LEFT] == 0) {
+                        // "left" rule is not defined but "start" rule is: use the "start" rule as
+                        // the "left" rule
+                        mRules[ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
+                    }
+                    mRules[ALIGN_PARENT_START] = 0;
+                }
+
+                if (mRules[ALIGN_PARENT_RIGHT] == 0) {
+                    if (mRules[ALIGN_PARENT_RIGHT] == 0) {
+                        // "right" rule is not defined but "end" rule is: use the "end" rule as the
+                        // "right" rule
+                        mRules[ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
+                    }
+                    mRules[ALIGN_PARENT_END] = 0;
+                }
+            } else {
+                // JB MR1+ case
+                if ((mRules[ALIGN_START] != 0 || mRules[ALIGN_END] != 0) &&
+                        (mRules[ALIGN_LEFT] != 0 || mRules[ALIGN_RIGHT] != 0)) {
+                    // "start"/"end" rules take precedence over "left"/"right" rules
+                    mRules[ALIGN_LEFT] = 0;
+                    mRules[ALIGN_RIGHT] = 0;
+                }
+                if (mRules[ALIGN_START] != 0) {
+                    // "start" rule resolved to "left" or "right" depending on the direction
+                    mRules[isLayoutRtl ? ALIGN_RIGHT : ALIGN_LEFT] = mRules[ALIGN_START];
+                    mRules[ALIGN_START] = 0;
+                }
+                if (mRules[ALIGN_END] != 0) {
+                    // "end" rule resolved to "left" or "right" depending on the direction
+                    mRules[isLayoutRtl ? ALIGN_LEFT : ALIGN_RIGHT] = mRules[ALIGN_END];
+                    mRules[ALIGN_END] = 0;
+                }
+
+                if ((mRules[START_OF] != 0 || mRules[END_OF] != 0) &&
+                        (mRules[LEFT_OF] != 0 || mRules[RIGHT_OF] != 0)) {
+                    // "start"/"end" rules take precedence over "left"/"right" rules
+                    mRules[LEFT_OF] = 0;
+                    mRules[RIGHT_OF] = 0;
+                }
+                if (mRules[START_OF] != 0) {
+                    // "start" rule resolved to "left" or "right" depending on the direction
+                    mRules[isLayoutRtl ? RIGHT_OF : LEFT_OF] = mRules[START_OF];
+                    mRules[START_OF] = 0;
+                }
+                if (mRules[END_OF] != 0) {
+                    // "end" rule resolved to "left" or "right" depending on the direction
+                    mRules[isLayoutRtl ? LEFT_OF : RIGHT_OF] = mRules[END_OF];
+                    mRules[END_OF] = 0;
+                }
+
+                if ((mRules[ALIGN_PARENT_START] != 0 || mRules[ALIGN_PARENT_END] != 0) &&
+                        (mRules[ALIGN_PARENT_LEFT] != 0 || mRules[ALIGN_PARENT_RIGHT] != 0)) {
+                    // "start"/"end" rules take precedence over "left"/"right" rules
+                    mRules[ALIGN_PARENT_LEFT] = 0;
+                    mRules[ALIGN_PARENT_RIGHT] = 0;
+                }
+                if (mRules[ALIGN_PARENT_START] != 0) {
+                    // "start" rule resolved to "left" or "right" depending on the direction
+                    mRules[isLayoutRtl ? ALIGN_PARENT_RIGHT : ALIGN_PARENT_LEFT] = mRules[ALIGN_PARENT_START];
+                    mRules[ALIGN_PARENT_START] = 0;
+                }
+                if (mRules[ALIGN_PARENT_END] != 0) {
+                    // "end" rule resolved to "left" or "right" depending on the direction
+                    mRules[isLayoutRtl ? ALIGN_PARENT_LEFT : ALIGN_PARENT_RIGHT] = mRules[ALIGN_PARENT_END];
+                    mRules[ALIGN_PARENT_END] = 0;
+                }
             }
             mRulesChanged = false;
         }
@@ -1464,11 +1586,11 @@
         public void resolveLayoutDirection(int layoutDirection) {
             final boolean isLayoutRtl = isLayoutRtl();
             if (isLayoutRtl) {
-                if (mStart != DEFAULT_RELATIVE) mRight = mStart;
-                if (mEnd != DEFAULT_RELATIVE) mLeft = mEnd;
+                if (mStart != DEFAULT_MARGIN_RELATIVE) mRight = mStart;
+                if (mEnd != DEFAULT_MARGIN_RELATIVE) mLeft = mEnd;
             } else {
-                if (mStart != DEFAULT_RELATIVE) mLeft = mStart;
-                if (mEnd != DEFAULT_RELATIVE) mRight = mEnd;
+                if (mStart != DEFAULT_MARGIN_RELATIVE) mLeft = mStart;
+                if (mEnd != DEFAULT_MARGIN_RELATIVE) mRight = mEnd;
             }
 
             if (hasRelativeRules() && layoutDirection != getLayoutDirection()) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 79fc51e..83e2e79 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -34,6 +34,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.StrictMode;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -2263,8 +2264,13 @@
      * @param value The value to pass to the method.
      */
     public void setUri(int viewId, String methodName, Uri value) {
-        // Resolve any filesystem path before sending remotely
-        value = value.getCanonicalUri();
+        if (value != null) {
+            // Resolve any filesystem path before sending remotely
+            value = value.getCanonicalUri();
+            if (StrictMode.vmFileUriExposureEnabled()) {
+                value.checkFileUriExposed("RemoteViews.setUri()");
+            }
+        }
         addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
     }
 
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 4045497..62afd2e 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -39,31 +39,26 @@
  * <p>
  * Here is how to use the action provider with custom backing file in a {@link MenuItem}:
  * </p>
- * <p>
  * <pre>
- * <code>
- *  // In Activity#onCreateOptionsMenu
- *  public boolean onCreateOptionsMenu(Menu menu) {
- *      // Get the menu item.
- *      MenuItem menuItem = menu.findItem(R.id.my_menu_item);
- *      // Get the provider and hold onto it to set/change the share intent.
- *      mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
- *      // Set history different from the default before getting the action
- *      // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls
- *      // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
- *      // line if using the default share history file is desired.
- *      mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
- *      . . .
- *  }
+ * // In Activity#onCreateOptionsMenu
+ * public boolean onCreateOptionsMenu(Menu menu) {
+ *     // Get the menu item.
+ *     MenuItem menuItem = menu.findItem(R.id.my_menu_item);
+ *     // Get the provider and hold onto it to set/change the share intent.
+ *     mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
+ *     // Set history different from the default before getting the action
+ *     // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls
+ *     // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
+ *     // line if using the default share history file is desired.
+ *     mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
+ *     . . .
+ * }
  *
- *  // Somewhere in the application.
- *  public void doShare(Intent shareIntent) {
- *      // When you want to share set the share intent.
- *      mShareActionProvider.setShareIntent(shareIntent);
- *  }
- * </pre>
- * </code>
- * </p>
+ * // Somewhere in the application.
+ * public void doShare(Intent shareIntent) {
+ *     // When you want to share set the share intent.
+ *     mShareActionProvider.setShareIntent(shareIntent);
+ * }</pre>
  * <p>
  * <strong>Note:</strong> While the sample snippet demonstrates how to use this provider
  * in the context of a menu item, the use of the provider is not limited to menu items.
@@ -245,9 +240,9 @@
      * call {@link android.app.Activity#invalidateOptionsMenu()} to recreate the
      * action view. You should <strong>not</strong> call
      * {@link android.app.Activity#invalidateOptionsMenu()} from
-     * {@link android.app.Activity#onCreateOptionsMenu(Menu)}."
-     * <p>
-     * <code>
+     * {@link android.app.Activity#onCreateOptionsMenu(Menu)}.
+     * </p>
+     * <pre>
      * private void doShare(Intent intent) {
      *     if (IMAGE.equals(intent.getMimeType())) {
      *         mShareActionProvider.setHistoryFileName(SHARE_IMAGE_HISTORY_FILE_NAME);
@@ -256,9 +251,7 @@
      *     }
      *     mShareActionProvider.setIntent(intent);
      *     invalidateOptionsMenu();
-     * }
-     * <code>
-     *
+     * }</pre>
      * @param shareHistoryFile The share history file name.
      */
     public void setShareHistoryFileName(String shareHistoryFile) {
@@ -269,16 +262,11 @@
     /**
      * Sets an intent with information about the share action. Here is a
      * sample for constructing a share intent:
-     * <p>
      * <pre>
-     * <code>
-     *  Intent shareIntent = new Intent(Intent.ACTION_SEND);
-     *  shareIntent.setType("image/*");
-     *  Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
-     *  shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());
-     * </pre>
-     * </code>
-     * </p>
+     * Intent shareIntent = new Intent(Intent.ACTION_SEND);
+     * shareIntent.setType("image/*");
+     * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
+     * shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());</pre>
      *
      * @param shareIntent The share intent.
      *
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index b6895a5..e3de0b9 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -494,20 +494,23 @@
 
         // Make selected view and position it
         mFirstPosition = mSelectedPosition;
-        View sel = makeAndAddView(mSelectedPosition);
-        int width = sel.getMeasuredWidth();
-        int selectedOffset = childrenLeft;
-        final int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
-                break;
-            case Gravity.RIGHT:
-                selectedOffset = childrenLeft + childrenWidth - width;
-                break;
+
+        if (mAdapter != null) {
+            View sel = makeAndAddView(mSelectedPosition);
+            int width = sel.getMeasuredWidth();
+            int selectedOffset = childrenLeft;
+            final int layoutDirection = getLayoutDirection();
+            final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+            switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                case Gravity.CENTER_HORIZONTAL:
+                    selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
+                    break;
+                case Gravity.RIGHT:
+                    selectedOffset = childrenLeft + childrenWidth - width;
+                    break;
+            }
+            sel.offsetLeftAndRight(selectedOffset);
         }
-        sel.offsetLeftAndRight(selectedOffset);
 
         // Flush any cached views that did not get reused above
         mRecycler.clear();
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 5bf21c0..a564c96 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -36,21 +36,24 @@
 import java.util.Calendar;
 import java.util.TimeZone;
 
+import libcore.icu.LocaleData;
+
 import static android.view.ViewDebug.ExportedProperty;
 import static android.widget.RemoteViews.*;
 
 /**
  * <p><code>TextClock</code> can display the current date and/or time as
  * a formatted string.</p>
- * 
+ *
  * <p>This view honors the 24-hour format system setting. As such, it is
  * possible and recommended to provide two different formatting patterns:
  * one to display the date/time in 24-hour mode and one to display the
- * date/time in 12-hour mode.</p>
- * 
+ * date/time in 12-hour mode. Most callers will want to use the defaults,
+ * though, which will be appropriate for the user's locale.</p>
+ *
  * <p>It is possible to determine whether the system is currently in
  * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p>
- * 
+ *
  * <p>The rules used by this widget to decide how to format the date and
  * time are the following:</p>
  * <ul>
@@ -58,22 +61,24 @@
  *         <ul>
  *             <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li>
  *             <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li>
- *             <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li>
+ *             <li>Otherwise, use a default value appropriate for the user's locale, such as {@code h:mm a}</li>
  *         </ul>
  *     </li>
  *     <li>In 12-hour mode:
  *         <ul>
  *             <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li>
  *             <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li>
- *             <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li>
+ *             <li>Otherwise, use a default value appropriate for the user's locale, such as {@code HH:mm}</li>
  *         </ul>
  *     </li>
  * </ul>
- * 
+ *
  * <p>The {@link CharSequence} instances used as formatting patterns when calling either
  * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can
- * contain styling information. To do so, use a {@link android.text.Spanned} object.</p>
- * 
+ * contain styling information. To do so, use a {@link android.text.Spanned} object.
+ * Note that if you customize these strings, it is your responsibility to supply strings
+ * appropriate for formatting dates and/or times in the user's locale.</p>
+ *
  * @attr ref android.R.styleable#TextClock_format12Hour
  * @attr ref android.R.styleable#TextClock_format24Hour
  * @attr ref android.R.styleable#TextClock_timeZone
@@ -81,32 +86,34 @@
 @RemoteView
 public class TextClock extends TextView {
     /**
-     * The default formatting pattern in 12-hour mode. This pattenr is used
+     * The default formatting pattern in 12-hour mode. This pattern is used
      * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern
      * or if no pattern was specified when creating an instance of this class.
-     * 
+     *
      * This default pattern shows only the time, hours and minutes, and an am/pm
      * indicator.
      *
      * @see #setFormat12Hour(CharSequence)
      * @see #getFormat12Hour()
+     * @deprecated Let the system use locale-appropriate defaults instead.
      */
-    public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa";
+    public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm a";
 
     /**
-     * The default formatting pattern in 24-hour mode. This pattenr is used
+     * The default formatting pattern in 24-hour mode. This pattern is used
      * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern
      * or if no pattern was specified when creating an instance of this class.
      *
      * This default pattern shows only the time, hours and minutes.
-     * 
-     * @see #setFormat24Hour(CharSequence) 
-     * @see #getFormat24Hour() 
+     *
+     * @see #setFormat24Hour(CharSequence)
+     * @see #getFormat24Hour()
+     * @deprecated Let the system use locale-appropriate defaults instead.
      */
-    public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm";
+    public static final CharSequence DEFAULT_FORMAT_24_HOUR = "H:mm";
 
-    private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR;
-    private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR;
+    private CharSequence mFormat12;
+    private CharSequence mFormat24;
 
     @ExportedProperty
     private CharSequence mFormat;
@@ -158,7 +165,7 @@
      * Creates a new clock using the default patterns
      * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR}
      * respectively for the 24-hour and 12-hour modes.
-     * 
+     *
      * @param context The Context the view is running in, through which it can
      *        access the current theme, resources, etc.
      */
@@ -171,7 +178,7 @@
     /**
      * Creates a new clock inflated from XML. This object's properties are
      * intialized from the attributes specified in XML.
-     * 
+     *
      * This constructor uses a default style of 0, so the only attribute values
      * applied are those in the Context's Theme and the given AttributeSet.
      *
@@ -201,14 +208,8 @@
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0);
         try {
-            CharSequence format;
-
-            format = a.getText(R.styleable.TextClock_format12Hour);
-            mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format;
-
-            format = a.getText(R.styleable.TextClock_format24Hour);
-            mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format;
-
+            mFormat12 = a.getText(R.styleable.TextClock_format12Hour);
+            mFormat24 = a.getText(R.styleable.TextClock_format24Hour);
             mTimeZone = a.getString(R.styleable.TextClock_timeZone);
         } finally {
             a.recycle();
@@ -218,6 +219,16 @@
     }
 
     private void init() {
+        if (mFormat12 == null || mFormat24 == null) {
+            LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
+            if (mFormat12 == null) {
+                mFormat12 = ld.timeFormat12;
+            }
+            if (mFormat24 == null) {
+                mFormat24 = ld.timeFormat24;
+            }
+        }
+
         createTime(mTimeZone);
         // Wait until onAttachedToWindow() to handle the ticker
         chooseFormat(false);
@@ -235,11 +246,11 @@
      * Returns the formatting pattern used to display the date and/or time
      * in 12-hour mode. The formatting pattern syntax is described in
      * {@link DateFormat}.
-     * 
+     *
      * @return A {@link CharSequence} or null.
-     * 
-     * @see #setFormat12Hour(CharSequence) 
-     * @see #is24HourModeEnabled() 
+     *
+     * @see #setFormat12Hour(CharSequence)
+     * @see #is24HourModeEnabled()
      */
     @ExportedProperty
     public CharSequence getFormat12Hour() {
@@ -257,12 +268,12 @@
      * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead.
      *
      * @param format A date/time formatting pattern as described in {@link DateFormat}
-     * 
+     *
      * @see #getFormat12Hour()
      * @see #is24HourModeEnabled()
      * @see #DEFAULT_FORMAT_12_HOUR
      * @see DateFormat
-     * 
+     *
      * @attr ref android.R.styleable#TextClock_format12Hour
      */
     @RemotableViewMethod
@@ -292,7 +303,7 @@
      * Specifies the formatting pattern used to display the date and/or time
      * in 24-hour mode. The formatting pattern syntax is described in
      * {@link DateFormat}.
-     * 
+     *
      * If this pattern is set to null, {@link #getFormat12Hour()} will be used
      * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns
      * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and
@@ -301,7 +312,7 @@
      * @param format A date/time formatting pattern as described in {@link DateFormat}
      *
      * @see #getFormat24Hour()
-     * @see #is24HourModeEnabled() 
+     * @see #is24HourModeEnabled()
      * @see #DEFAULT_FORMAT_24_HOUR
      * @see DateFormat
      *
@@ -317,22 +328,22 @@
 
     /**
      * Indicates whether the system is currently using the 24-hour mode.
-     * 
+     *
      * When the system is in 24-hour mode, this view will use the pattern
      * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern
      * returned by {@link #getFormat12Hour()} is used instead.
-     * 
+     *
      * If either one of the formats is null, the other format is used. If
      * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR}
      * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead.
-     * 
+     *
      * @return true if time should be displayed in 24-hour format, false if it
      *         should be displayed in 12-hour format.
-     * 
+     *
      * @see #setFormat12Hour(CharSequence)
-     * @see #getFormat12Hour() 
+     * @see #getFormat12Hour()
      * @see #setFormat24Hour(CharSequence)
-     * @see #getFormat24Hour() 
+     * @see #getFormat24Hour()
      */
     public boolean is24HourModeEnabled() {
         return DateFormat.is24HourFormat(getContext());
@@ -340,13 +351,13 @@
 
     /**
      * Indicates which time zone is currently used by this view.
-     * 
+     *
      * @return The ID of the current time zone or null if the default time zone,
      *         as set by the user, must be used
      *
      * @see TimeZone
      * @see java.util.TimeZone#getAvailableIDs()
-     * @see #setTimeZone(String) 
+     * @see #setTimeZone(String)
      */
     public String getTimeZone() {
         return mTimeZone;
@@ -378,7 +389,7 @@
     /**
      * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
      * depending on whether the user has selected 24-hour format.
-     * 
+     *
      * Calling this method does not schedule or unschedule the time ticker.
      */
     private void chooseFormat() {
@@ -398,17 +409,19 @@
     /**
      * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
      * depending on whether the user has selected 24-hour format.
-     * 
+     *
      * @param handleTicker true if calling this method should schedule/unschedule the
      *                     time ticker, false otherwise
      */
     private void chooseFormat(boolean handleTicker) {
         final boolean format24Requested = is24HourModeEnabled();
 
+        LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
+
         if (format24Requested) {
-            mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR);
+            mFormat = abc(mFormat24, mFormat12, ld.timeFormat24);
         } else {
-            mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR);
+            mFormat = abc(mFormat12, mFormat24, ld.timeFormat12);
         }
 
         boolean hadSeconds = mHasSeconds;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index adacef2..52b7a81 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -136,6 +136,8 @@
 import java.util.Locale;
 import java.util.concurrent.locks.ReentrantLock;
 
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
 /**
  * Displays text to the user and optionally allows them to edit it.  A TextView
  * is a complete text editor, however the basic class is configured to not
@@ -294,6 +296,10 @@
         Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
                 mDrawableStart, mDrawableEnd, mDrawableError, mDrawableTemp;
 
+        Drawable mDrawableLeftInitial, mDrawableRightInitial;
+        boolean mIsRtlCompatibilityMode;
+        boolean mOverride;
+
         int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
                 mDrawableSizeStart, mDrawableSizeEnd, mDrawableSizeError, mDrawableSizeTemp;
 
@@ -304,38 +310,64 @@
 
         int mDrawableSaved = DRAWABLE_NONE;
 
+        public Drawables(Context context) {
+            final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+            mIsRtlCompatibilityMode = (targetSdkVersion < JELLY_BEAN_MR1 ||
+                !context.getApplicationInfo().hasRtlSupport());
+            mOverride = false;
+        }
+
         public void resolveWithLayoutDirection(int layoutDirection) {
-            switch(layoutDirection) {
-                case LAYOUT_DIRECTION_RTL:
-                    if (mDrawableStart != null) {
-                        mDrawableRight = mDrawableStart;
+            // First reset "left" and "right" drawables to their initial values
+            mDrawableLeft = mDrawableLeftInitial;
+            mDrawableRight = mDrawableRightInitial;
 
-                        mDrawableSizeRight = mDrawableSizeStart;
-                        mDrawableHeightRight = mDrawableHeightStart;
-                    }
-                    if (mDrawableEnd != null) {
-                        mDrawableLeft = mDrawableEnd;
+            if (mIsRtlCompatibilityMode) {
+                // Use "start" drawable as "left" drawable if the "left" drawable was not defined
+                if (mDrawableStart != null && mDrawableLeft == null) {
+                    mDrawableLeft = mDrawableStart;
+                    mDrawableSizeLeft = mDrawableSizeStart;
+                    mDrawableHeightLeft = mDrawableHeightStart;
+                }
+                // Use "end" drawable as "right" drawable if the "right" drawable was not defined
+                if (mDrawableEnd != null && mDrawableRight == null) {
+                    mDrawableRight = mDrawableEnd;
+                    mDrawableSizeRight = mDrawableSizeEnd;
+                    mDrawableHeightRight = mDrawableHeightEnd;
+                }
+            } else {
+                // JB-MR1+ normal case: "start" / "end" drawables are overriding "left" / "right"
+                // drawable if and only if they have been defined
+                switch(layoutDirection) {
+                    case LAYOUT_DIRECTION_RTL:
+                        if (mOverride) {
+                            mDrawableRight = mDrawableStart;
+                            mDrawableSizeRight = mDrawableSizeStart;
+                            mDrawableHeightRight = mDrawableHeightStart;
+                        }
 
-                        mDrawableSizeLeft = mDrawableSizeEnd;
-                        mDrawableHeightLeft = mDrawableHeightEnd;
-                    }
-                    break;
+                        if (mOverride) {
+                            mDrawableLeft = mDrawableEnd;
+                            mDrawableSizeLeft = mDrawableSizeEnd;
+                            mDrawableHeightLeft = mDrawableHeightEnd;
+                        }
+                        break;
 
-                case LAYOUT_DIRECTION_LTR:
-                default:
-                    if (mDrawableStart != null) {
-                        mDrawableLeft = mDrawableStart;
+                    case LAYOUT_DIRECTION_LTR:
+                    default:
+                        if (mOverride) {
+                            mDrawableLeft = mDrawableStart;
+                            mDrawableSizeLeft = mDrawableSizeStart;
+                            mDrawableHeightLeft = mDrawableHeightStart;
+                        }
 
-                        mDrawableSizeLeft = mDrawableSizeStart;
-                        mDrawableHeightLeft = mDrawableHeightStart;
-                    }
-                    if (mDrawableEnd != null) {
-                        mDrawableRight = mDrawableEnd;
-
-                        mDrawableSizeRight = mDrawableSizeEnd;
-                        mDrawableHeightRight = mDrawableHeightEnd;
-                    }
-                    break;
+                        if (mOverride) {
+                            mDrawableRight = mDrawableEnd;
+                            mDrawableSizeRight = mDrawableSizeEnd;
+                            mDrawableHeightRight = mDrawableHeightEnd;
+                        }
+                        break;
+                }
             }
             applyErrorDrawableIfNeeded(layoutDirection);
             updateDrawablesLayoutDirection(layoutDirection);
@@ -1154,6 +1186,7 @@
                 bufferType = BufferType.SPANNABLE;
         }
 
+        // This call will save the initial left/right drawables
         setCompoundDrawablesWithIntrinsicBounds(
             drawableLeft, drawableTop, drawableRight, drawableBottom);
         setRelativeDrawablesIfNeeded(drawableStart, drawableEnd);
@@ -1302,8 +1335,9 @@
         if (hasRelativeDrawables) {
             Drawables dr = mDrawables;
             if (dr == null) {
-                mDrawables = dr = new Drawables();
+                mDrawables = dr = new Drawables(getContext());
             }
+            mDrawables.mOverride = true;
             final Rect compoundRect = dr.mCompoundRect;
             int[] state = getDrawableState();
             if (start != null) {
@@ -1876,9 +1910,11 @@
             }
         } else {
             if (dr == null) {
-                mDrawables = dr = new Drawables();
+                mDrawables = dr = new Drawables(getContext());
             }
 
+            mDrawables.mOverride = false;
+
             if (dr.mDrawableLeft != left && dr.mDrawableLeft != null) {
                 dr.mDrawableLeft.setCallback(null);
             }
@@ -1945,6 +1981,12 @@
             }
         }
 
+        // Save initial left/right drawables
+        if (dr != null) {
+            dr.mDrawableLeftInitial = left;
+            dr.mDrawableRightInitial = right;
+        }
+
         invalidate();
         requestLayout();
     }
@@ -2045,9 +2087,11 @@
             }
         } else {
             if (dr == null) {
-                mDrawables = dr = new Drawables();
+                mDrawables = dr = new Drawables(getContext());
             }
 
+            mDrawables.mOverride = true;
+
             if (dr.mDrawableStart != start && dr.mDrawableStart != null) {
                 dr.mDrawableStart.setCallback(null);
             }
@@ -2114,6 +2158,7 @@
             }
         }
 
+        resetResolvedDrawables();
         resolveDrawables();
         invalidate();
         requestLayout();
@@ -2138,7 +2183,6 @@
     @android.view.RemotableViewMethod
     public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
             int bottom) {
-        resetResolvedDrawables();
         final Resources resources = getContext().getResources();
         setCompoundDrawablesRelativeWithIntrinsicBounds(
                 start != 0 ? resources.getDrawable(start) : null,
@@ -2161,7 +2205,6 @@
     public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top,
             Drawable end, Drawable bottom) {
 
-        resetResolvedDrawables();
         if (start != null) {
             start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
         }
@@ -2230,7 +2273,7 @@
             }
         } else {
             if (dr == null) {
-                mDrawables = dr = new Drawables();
+                mDrawables = dr = new Drawables(getContext());
             }
             dr.mDrawablePadding = pad;
         }
@@ -4751,7 +4794,8 @@
 
     @Override
     public boolean hasOverlappingRendering() {
-        return (getBackground() != null || mText instanceof Spannable || hasSelection());
+        return ((getBackground() != null && getBackground().getCurrent() != null)
+                || mText instanceof Spannable || hasSelection());
     }
 
     /**
@@ -8813,11 +8857,11 @@
         }
 
         public void drawTextRun(Canvas c, int start, int end,
-                int contextStart, int contextEnd, float x, float y, Paint p) {
+                int contextStart, int contextEnd, float x, float y, int flags, Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
-                    contextCount, x, y, p);
+                    contextCount, x, y, flags, p);
         }
 
         public float measureText(int start, int end, Paint p) {
@@ -8829,20 +8873,20 @@
         }
 
         public float getTextRunAdvances(int start, int end, int contextStart,
-                int contextEnd, float[] advances, int advancesIndex,
+                int contextEnd, int flags, float[] advances, int advancesIndex,
                 Paint p) {
             int count = end - start;
             int contextCount = contextEnd - contextStart;
             return p.getTextRunAdvances(mChars, start + mStart, count,
-                    contextStart + mStart, contextCount, advances,
+                    contextStart + mStart, contextCount, flags, advances,
                     advancesIndex);
         }
 
-        public int getTextRunCursor(int contextStart, int contextEnd,
+        public int getTextRunCursor(int contextStart, int contextEnd, int flags,
                 int offset, int cursorOpt, Paint p) {
             int contextCount = contextEnd - contextStart;
             return p.getTextRunCursor(mChars, contextStart + mStart,
-                    contextCount, offset + mStart, cursorOpt);
+                    contextCount, flags, offset + mStart, cursorOpt);
         }
     }
 
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index db20549..acbb2b1 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -812,6 +812,26 @@
         return mActionView != null && mActionView.isTitleTruncated();
     }
 
+    @Override
+    public void setHomeAsUpIndicator(Drawable indicator) {
+        mActionView.setHomeAsUpIndicator(indicator);
+    }
+
+    @Override
+    public void setHomeAsUpIndicator(int resId) {
+        mActionView.setHomeAsUpIndicator(resId);
+    }
+
+    @Override
+    public void setHomeActionContentDescription(CharSequence description) {
+        mActionView.setHomeActionContentDescription(description);
+    }
+
+    @Override
+    public void setHomeActionContentDescription(int resId) {
+        mActionView.setHomeActionContentDescription(resId);
+    }
+
     /**
      * @hide 
      */
diff --git a/core/java/com/android/internal/backup/IObbBackupService.aidl b/core/java/com/android/internal/backup/IObbBackupService.aidl
new file mode 100644
index 0000000..426dbc4
--- /dev/null
+++ b/core/java/com/android/internal/backup/IObbBackupService.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.backup;
+ 
+import android.app.backup.IBackupManager;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Interface for the Backup Manager Service to communicate with a helper service that
+ * handles local (whole-file) backup & restore of OBB content on behalf of applications.
+ * This can't be done within the Backup Manager Service itself because of the restrictions
+ * on system-user access to external storage, and can't be left to the apps because even
+ * apps that do not have permission to access external storage in the usual way can still
+ * use OBBs.
+ *
+ * {@hide}
+ */
+oneway interface IObbBackupService {
+    /*
+     * Back up a package's OBB directory tree
+     */
+    void backupObbs(in String packageName, in ParcelFileDescriptor data,
+            int token, in IBackupManager callbackBinder);
+
+    /*
+     * Restore an OBB file for the given package from the incoming stream
+     */
+    void restoreObbFile(in String pkgName, in ParcelFileDescriptor data,
+            long fileSize, int type, in String path, long mode, long mtime,
+            int token, in IBackupManager callbackBinder);
+}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index eed3e67..eb2d1fe 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -27,6 +27,7 @@
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.util.Log;
 
 import com.android.org.bouncycastle.util.encoders.Base64;
@@ -64,6 +65,10 @@
 
     public LocalTransport(Context context) {
         mContext = context;
+        mDataDir.mkdirs();
+        if (!SELinux.restorecon(mDataDir)) {
+            Log.e(TAG, "SELinux restorecon failed for " + mDataDir);
+        }
     }
 
     public Intent configurationIntent() {
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
new file mode 100644
index 0000000..e26b27d
--- /dev/null
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -0,0 +1,146 @@
+/*
+**
+** 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.
+*/
+
+package com.android.internal.os;
+
+import java.io.PrintStream;
+
+public abstract class BaseCommand {
+
+    protected String[] mArgs;
+    private int mNextArg;
+    private String mCurArgData;
+
+    // These are magic strings understood by the Eclipse plugin.
+    public static final String FATAL_ERROR_CODE = "Error type 1";
+    public static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
+    public static final String NO_CLASS_ERROR_CODE = "Error type 3";
+
+    /**
+     * Call to run the command.
+     */
+    public void run(String[] args) {
+        if (args.length < 1) {
+            onShowUsage(System.out);
+            return;
+        }
+
+        mArgs = args;
+        mNextArg = 0;
+        mCurArgData = null;
+
+        try {
+            onRun();
+        } catch (IllegalArgumentException e) {
+            onShowUsage(System.err);
+            System.err.println();
+            System.err.println("Error: " + e.getMessage());
+        } catch (Exception e) {
+            e.printStackTrace(System.err);
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Convenience to show usage information to error output.
+     */
+    public void showUsage() {
+        onShowUsage(System.err);
+    }
+
+    /**
+     * Convenience to show usage information to error output along
+     * with an error message.
+     */
+    public void showError(String message) {
+        onShowUsage(System.err);
+        System.err.println();
+        System.err.println(message);
+    }
+
+    /**
+     * Implement the command.
+     */
+    public abstract void onRun() throws Exception;
+
+    /**
+     * Print help text for the command.
+     */
+    public abstract void onShowUsage(PrintStream out);
+
+    /**
+     * Return the next option on the command line -- that is an argument that
+     * starts with '-'.  If the next argument is not an option, null is returned.
+     */
+    public String nextOption() {
+        if (mCurArgData != null) {
+            String prev = mArgs[mNextArg - 1];
+            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+        }
+        if (mNextArg >= mArgs.length) {
+            return null;
+        }
+        String arg = mArgs[mNextArg];
+        if (!arg.startsWith("-")) {
+            return null;
+        }
+        mNextArg++;
+        if (arg.equals("--")) {
+            return null;
+        }
+        if (arg.length() > 1 && arg.charAt(1) != '-') {
+            if (arg.length() > 2) {
+                mCurArgData = arg.substring(2);
+                return arg.substring(0, 2);
+            } else {
+                mCurArgData = null;
+                return arg;
+            }
+        }
+        mCurArgData = null;
+        return arg;
+    }
+
+    /**
+     * Return the next argument on the command line, whatever it is; if there are
+     * no arguments left, return null.
+     */
+    public String nextArg() {
+        if (mCurArgData != null) {
+            String arg = mCurArgData;
+            mCurArgData = null;
+            return arg;
+        } else if (mNextArg < mArgs.length) {
+            return mArgs[mNextArg++];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Return the next argument on the command line, whatever it is; if there are
+     * no arguments left, throws an IllegalArgumentException to report this to the user.
+     */
+    public String nextArgRequired() {
+        String arg = nextArg();
+        if (arg == null) {
+            String prev = mArgs[mNextArg - 1];
+            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
+        }
+        return arg;
+    }
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 780f5b3..58b15e2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -17,7 +17,7 @@
 package com.android.internal.statusbar;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
+import android.service.notification.StatusBarNotification;
 
 /** @hide */
 oneway interface IStatusBar
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 04e5bc9..c98ba8d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -19,7 +19,7 @@
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
+import android.service.notification.StatusBarNotification;
 
 /** @hide */
 interface IStatusBarService
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.aidl b/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
deleted file mode 100644
index bd9e89c..0000000
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
-
-package com.android.internal.statusbar;
-
-parcelable StatusBarNotification;
-
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java
deleted file mode 100644
index 23e87fc..0000000
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2008 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.internal.statusbar;
-
-import android.app.Notification;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-
-/**
- * Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
- * the IStatusBar (in System UI).
- */
-public class StatusBarNotification implements Parcelable {
-    public final String pkg;
-    public final String basePkg;
-    public final int id;
-    public final String tag;
-    public final int uid;
-    public final int initialPid;
-    // TODO: make this field private and move callers to an accessor that
-    // ensures sourceUser is applied.
-    public final Notification notification;
-    public final int score;
-    public final UserHandle user;
-    public final long postTime;
-
-    /** This is temporarily needed for the JB MR1 PDK. */
-    @Deprecated
-    public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
-            Notification notification) {
-        this(pkg, id, tag, uid, initialPid, score, notification, UserHandle.OWNER);
-    }
-
-    public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
-            Notification notification, UserHandle user) {
-        this(pkg, null, id, tag, uid, initialPid, score, notification, user);
-    }
-
-    public StatusBarNotification(String pkg, String basePkg, int id, String tag, int uid,
-            int initialPid, int score, Notification notification, UserHandle user) {
-        this(pkg, basePkg, id, tag, uid, initialPid, score, notification, user,
-                System.currentTimeMillis());
-    }
-
-    public StatusBarNotification(String pkg, String basePkg, int id, String tag, int uid,
-            int initialPid, int score, Notification notification, UserHandle user,
-            long postTime) {
-        if (pkg == null) throw new NullPointerException();
-        if (notification == null) throw new NullPointerException();
-
-        this.pkg = pkg;
-        this.basePkg = pkg;
-        this.id = id;
-        this.tag = tag;
-        this.uid = uid;
-        this.initialPid = initialPid;
-        this.score = score;
-        this.notification = notification;
-        this.user = user;
-        this.notification.setUser(user);
-
-        this.postTime = postTime;
-    }
-
-    public StatusBarNotification(Parcel in) {
-        this.pkg = in.readString();
-        this.basePkg = in.readString();
-        this.id = in.readInt();
-        if (in.readInt() != 0) {
-            this.tag = in.readString();
-        } else {
-            this.tag = null;
-        }
-        this.uid = in.readInt();
-        this.initialPid = in.readInt();
-        this.score = in.readInt();
-        this.notification = new Notification(in);
-        this.user = UserHandle.readFromParcel(in);
-        this.notification.setUser(this.user);
-        this.postTime = in.readLong();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(this.pkg);
-        out.writeString(this.basePkg);
-        out.writeInt(this.id);
-        if (this.tag != null) {
-            out.writeInt(1);
-            out.writeString(this.tag);
-        } else {
-            out.writeInt(0);
-        }
-        out.writeInt(this.uid);
-        out.writeInt(this.initialPid);
-        out.writeInt(this.score);
-        this.notification.writeToParcel(out, flags);
-        user.writeToParcel(out, flags);
-
-        out.writeLong(this.postTime);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<StatusBarNotification> CREATOR
-            = new Parcelable.Creator<StatusBarNotification>()
-    {
-        public StatusBarNotification createFromParcel(Parcel parcel)
-        {
-            return new StatusBarNotification(parcel);
-        }
-
-        public StatusBarNotification[] newArray(int size)
-        {
-            return new StatusBarNotification[size];
-        }
-    };
-
-    @Override
-    public StatusBarNotification clone() {
-        return new StatusBarNotification(this.pkg, this.basePkg,
-                this.id, this.tag, this.uid, this.initialPid,
-                this.score, this.notification.clone(), this.user, this.postTime);
-    }
-
-    @Override
-    public String toString() {
-        return String.format(
-                "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d: %s)",
-                this.pkg, this.user, this.id, this.tag,
-                this.score, this.notification);
-    }
-
-    public boolean isOngoing() {
-        return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
-    }
-
-    public boolean isClearable() {
-        return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
-                && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
-    }
-
-    /** Returns a userHandle for the instance of the app that posted this notification. */
-    public int getUserId() {
-        return this.user.getIdentifier();
-    }
-}
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index d44df0c..9137d3c 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -79,6 +79,10 @@
      * @return true if they're equal, false otherwise
      */
     public static boolean equals(byte[] array1, byte[] array2, int length) {
+        if (length < 0) {
+            throw new IllegalArgumentException();
+        }
+
         if (array1 == array2) {
             return true;
         }
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 7c2b1b5..b380403 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -45,11 +45,13 @@
     public static final int BASE_WIFI_P2P_SERVICE                                   = 0x00023000;
     public static final int BASE_WIFI_MONITOR                                       = 0x00024000;
     public static final int BASE_WIFI_MANAGER                                       = 0x00025000;
+    public static final int BASE_WIFI_CONTROLLER                                    = 0x00026000;
     public static final int BASE_DHCP                                               = 0x00030000;
     public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
     public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
     public static final int BASE_DATA_CONNECTION_TRACKER                            = 0x00042000;
     public static final int BASE_DNS_PINGER                                         = 0x00050000;
     public static final int BASE_NSD_MANAGER                                        = 0x00060000;
+    public static final int BASE_NETWORK_STATE_TRACKER                              = 0x00070000;
     //TODO: define all used protocols
 }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 58d4aa7..dd57ef4 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1257,6 +1257,15 @@
     }
 
     /**
+     * Constructor creates a StateMachine using the handler.
+     *
+     * @param name of the state machine
+     */
+    protected StateMachine(String name, Handler handler) {
+        initStateMachine(name, handler.getLooper());
+    }
+
+    /**
      * Add a new state to the state machine
      * @param state the state to add
      * @param parent the parent of state
@@ -1549,6 +1558,24 @@
      *
      * @param what  is assigned to Message.what
      * @param arg1  is assigned to Message.arg1
+     * @return  A Message object from the global pool
+     */
+    public final Message obtainMessage(int what, int arg1) {
+        // use this obtain so we don't match the obtain(h, what, Object) method
+        return Message.obtain(mSmHandler, what, arg1, 0);
+    }
+
+    /**
+     * Get a message and set Message.target state machine handler,
+     * what, arg1 and arg2
+     *
+     * Note: The handler can be null if the state machine has quit,
+     * which means target will be null and may cause a AndroidRuntimeException
+     * in MessageQueue#enqueMessage if sent directly or if sent using
+     * StateMachine#sendMessage the message will just be ignored.
+     *
+     * @param what  is assigned to Message.what
+     * @param arg1  is assigned to Message.arg1
      * @param arg2  is assigned to Message.arg2
      * @return  A Message object from the global pool
      */
@@ -1606,6 +1633,45 @@
      *
      * Message is ignored if state machine has quit.
      */
+    public final void sendMessage(int what, int arg1) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessage(obtainMessage(what, arg1));
+    }
+
+    /**
+     * Enqueue a message to this state machine.
+     *
+     * Message is ignored if state machine has quit.
+     */
+    public final void sendMessage(int what, int arg1, int arg2) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessage(obtainMessage(what, arg1, arg2));
+    }
+
+    /**
+     * Enqueue a message to this state machine.
+     *
+     * Message is ignored if state machine has quit.
+     */
+    public final void sendMessage(int what, int arg1, int arg2, Object obj) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessage(obtainMessage(what, arg1, arg2, obj));
+    }
+
+    /**
+     * Enqueue a message to this state machine.
+     *
+     * Message is ignored if state machine has quit.
+     */
     public final void sendMessage(Message msg) {
         // mSmHandler can be null if the state machine has quit.
         SmHandler smh = mSmHandler;
@@ -1645,6 +1711,46 @@
      *
      * Message is ignored if state machine has quit.
      */
+    public final void sendMessageDelayed(int what, int arg1, long delayMillis) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageDelayed(obtainMessage(what, arg1), delayMillis);
+    }
+
+    /**
+     * Enqueue a message to this state machine after a delay.
+     *
+     * Message is ignored if state machine has quit.
+     */
+    public final void sendMessageDelayed(int what, int arg1, int arg2, long delayMillis) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageDelayed(obtainMessage(what, arg1, arg2), delayMillis);
+    }
+
+    /**
+     * Enqueue a message to this state machine after a delay.
+     *
+     * Message is ignored if state machine has quit.
+     */
+    public final void sendMessageDelayed(int what, int arg1, int arg2, Object obj,
+            long delayMillis) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageDelayed(obtainMessage(what, arg1, arg2, obj), delayMillis);
+    }
+
+    /**
+     * Enqueue a message to this state machine after a delay.
+     *
+     * Message is ignored if state machine has quit.
+     */
     public final void sendMessageDelayed(Message msg, long delayMillis) {
         // mSmHandler can be null if the state machine has quit.
         SmHandler smh = mSmHandler;
@@ -1659,6 +1765,20 @@
      *
      * Message is ignored if state machine has quit.
      */
+    protected final void sendMessageAtFrontOfQueue(int what) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageAtFrontOfQueue(obtainMessage(what));
+    }
+
+    /**
+     * Enqueue a message to the front of the queue for this state machine.
+     * Protected, may only be called by instances of StateMachine.
+     *
+     * Message is ignored if state machine has quit.
+     */
     protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
         // mSmHandler can be null if the state machine has quit.
         SmHandler smh = mSmHandler;
@@ -1673,12 +1793,41 @@
      *
      * Message is ignored if state machine has quit.
      */
-    protected final void sendMessageAtFrontOfQueue(int what) {
+    protected final void sendMessageAtFrontOfQueue(int what, int arg1) {
         // mSmHandler can be null if the state machine has quit.
         SmHandler smh = mSmHandler;
         if (smh == null) return;
 
-        smh.sendMessageAtFrontOfQueue(obtainMessage(what));
+        smh.sendMessageAtFrontOfQueue(obtainMessage(what, arg1));
+    }
+
+
+    /**
+     * Enqueue a message to the front of the queue for this state machine.
+     * Protected, may only be called by instances of StateMachine.
+     *
+     * Message is ignored if state machine has quit.
+     */
+    protected final void sendMessageAtFrontOfQueue(int what, int arg1, int arg2) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageAtFrontOfQueue(obtainMessage(what, arg1, arg2));
+    }
+
+    /**
+     * Enqueue a message to the front of the queue for this state machine.
+     * Protected, may only be called by instances of StateMachine.
+     *
+     * Message is ignored if state machine has quit.
+     */
+    protected final void sendMessageAtFrontOfQueue(int what, int arg1, int arg2, Object obj) {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        smh.sendMessageAtFrontOfQueue(obtainMessage(what, arg1, arg2, obj));
     }
 
     /**
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 93f6cf6..fa35308 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.util;
 
+import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -24,6 +25,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.ProtocolException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -32,11 +34,8 @@
 import java.util.Map;
 import java.util.Set;
 
-import android.util.Xml;
-
 /** {@hide} */
-public class XmlUtils
-{
+public class XmlUtils {
 
     public static void skipCurrentTag(XmlPullParser parser)
             throws XmlPullParserException, IOException {
@@ -900,4 +899,42 @@
             }
         }
     }
+
+    public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
+        final String value = in.getAttributeValue(null, name);
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
+        }
+    }
+
+    public static void writeIntAttribute(XmlSerializer out, String name, int value)
+            throws IOException {
+        out.attribute(null, name, Integer.toString(value));
+    }
+
+    public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
+        final String value = in.getAttributeValue(null, name);
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
+        }
+    }
+
+    public static void writeLongAttribute(XmlSerializer out, String name, long value)
+            throws IOException {
+        out.attribute(null, name, Long.toString(value));
+    }
+
+    public static boolean readBooleanAttribute(XmlPullParser in, String name) {
+        final String value = in.getAttributeValue(null, name);
+        return Boolean.parseBoolean(value);
+    }
+
+    public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
+            throws IOException {
+        out.attribute(null, name, Boolean.toString(value));
+    }
 }
diff --git a/core/java/com/android/internal/view/IInputConnectionCallback.aidl b/core/java/com/android/internal/view/IInputConnectionCallback.aidl
deleted file mode 100644
index 5b5b3df..0000000
--- a/core/java/com/android/internal/view/IInputConnectionCallback.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2008 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.internal.view;
-
-import android.graphics.Rect;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.inputmethod.TextBoxAttribute;
-import com.android.internal.view.IInputContext;
-import android.os.IBinder;
-
-/**
- * {@hide}
- */
-oneway interface IInputMethodCallback {
-    void finishedEvent(int seq, boolean handled);
-}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index c7fcab8..77456da 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -16,17 +16,15 @@
 
 package com.android.internal.view;
 
-import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.ResultReceiver;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
+import android.view.InputChannel;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputMethodSubtype;
 import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionCallback;
 
 /**
  * Top-level interface to an input method component (implemented in a
@@ -35,23 +33,23 @@
  */
 oneway interface IInputMethod {
     void attachToken(IBinder token);
-    
+
     void bindInput(in InputBinding binding);
-    
+
     void unbindInput();
 
     void startInput(in IInputContext inputContext, in EditorInfo attribute);
 
     void restartInput(in IInputContext inputContext, in EditorInfo attribute);
 
-    void createSession(IInputMethodCallback callback);
-    
+    void createSession(in InputChannel channel, IInputSessionCallback callback);
+
     void setSessionEnabled(IInputMethodSession session, boolean enabled);
-    
+
     void revokeSession(IInputMethodSession session);
-    
+
     void showSoftInput(int flags, in ResultReceiver resultReceiver);
-    
+
     void hideSoftInput(int flags, in ResultReceiver resultReceiver);
 
     void changeInputMethodSubtype(in InputMethodSubtype subtype);
diff --git a/core/java/com/android/internal/view/IInputMethodCallback.aidl b/core/java/com/android/internal/view/IInputMethodCallback.aidl
deleted file mode 100644
index 480cc0e..0000000
--- a/core/java/com/android/internal/view/IInputMethodCallback.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2008 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.internal.view;
-
-import android.graphics.Rect;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodSession;
-import android.os.IBinder;
-
-/**
- * Helper interface for IInputMethod to allow the input method to call back
- * to its client with results from incoming calls.
- * {@hide}
- */
-oneway interface IInputMethodCallback {
-    void finishedEvent(int seq, boolean handled);
-    void sessionCreated(IInputMethodSession session);
-}
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index cdec254..90210ce 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -22,7 +22,6 @@
 import android.view.MotionEvent;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.ExtractedText;
-import com.android.internal.view.IInputMethodCallback;
 
 /**
  * Sub-interface of IInputMethod which is safe to give to client applications.
@@ -40,14 +39,8 @@
     void viewClicked(boolean focusChanged);
 
     void updateCursor(in Rect newCursor);
-    
+
     void displayCompletions(in CompletionInfo[] completions);
-    
-    void dispatchKeyEvent(int seq, in KeyEvent event, IInputMethodCallback callback);
-
-    void dispatchTrackballEvent(int seq, in MotionEvent event, IInputMethodCallback callback);
-
-    void dispatchGenericMotionEvent(int seq, in MotionEvent event, IInputMethodCallback callback);
 
     void appPrivateCommand(String action, in Bundle data);
 
diff --git a/core/java/com/android/internal/view/IInputSessionCallback.aidl b/core/java/com/android/internal/view/IInputSessionCallback.aidl
new file mode 100644
index 0000000..2b48f33
--- /dev/null
+++ b/core/java/com/android/internal/view/IInputSessionCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.view;
+
+import com.android.internal.view.IInputMethodSession;
+
+/**
+ * Helper interface for IInputMethod to allow the input method to notify the client when a new
+ * session has been created.
+ * {@hide}
+ */
+
+oneway interface IInputSessionCallback {
+    void sessionCreated(IInputMethodSession session);
+}
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 658f098..14afe21 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.InputChannel;
 
 /**
  * Bundle of information returned by input method manager about a successful
@@ -30,7 +31,12 @@
      * The input method service.
      */
     public final IInputMethodSession method;
-    
+
+    /**
+     * The input channel used to send input events to this IME.
+     */
+    public final InputChannel channel;
+
     /**
      * The ID for this input method, as found in InputMethodInfo; null if
      * no input method will be bound.
@@ -42,18 +48,25 @@
      */
     public final int sequence;
     
-    public InputBindResult(IInputMethodSession _method, String _id, int _sequence) {
+    public InputBindResult(IInputMethodSession _method, InputChannel _channel,
+            String _id, int _sequence) {
         method = _method;
+        channel = _channel;
         id = _id;
         sequence = _sequence;
     }
     
     InputBindResult(Parcel source) {
         method = IInputMethodSession.Stub.asInterface(source.readStrongBinder());
+        if (source.readInt() != 0) {
+            channel = InputChannel.CREATOR.createFromParcel(source);
+        } else {
+            channel = null;
+        }
         id = source.readString();
         sequence = source.readInt();
     }
-    
+
     @Override
     public String toString() {
         return "InputBindResult{" + method + " " + id
@@ -62,12 +75,19 @@
 
     /**
      * Used to package this object into a {@link Parcel}.
-     * 
+     *
      * @param dest The {@link Parcel} to be written.
      * @param flags The flags used for parceling.
      */
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeStrongInterface(method);
+        if (channel != null) {
+            dest.writeInt(1);
+            channel.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
         dest.writeString(id);
         dest.writeInt(sequence);
     }
@@ -75,17 +95,21 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final Parcelable.Creator<InputBindResult> CREATOR = new Parcelable.Creator<InputBindResult>() {
+    public static final Parcelable.Creator<InputBindResult> CREATOR =
+            new Parcelable.Creator<InputBindResult>() {
+        @Override
         public InputBindResult createFromParcel(Parcel source) {
             return new InputBindResult(source);
         }
 
+        @Override
         public InputBindResult[] newArray(int size) {
             return new InputBindResult[size];
         }
     };
 
+    @Override
     public int describeContents() {
-        return 0;
+        return channel != null ? channel.describeContents() : 0;
     }
 }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index 2685046..7ca6c1b 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -107,7 +107,7 @@
     }
 
     public CharSequence getTitleCondensed() {
-        return mTitleCondensed;
+        return mTitleCondensed != null ? mTitleCondensed : mTitle;
     }
 
     public boolean hasSubMenu() {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 6bb7ac7..59ff597 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -36,7 +36,6 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -94,6 +93,8 @@
     private CharSequence mSubtitle;
     private Drawable mIcon;
     private Drawable mLogo;
+    private CharSequence mHomeDescription;
+    private int mHomeDescriptionRes;
 
     private HomeView mHomeLayout;
     private HomeView mExpandedHomeLayout;
@@ -125,6 +126,7 @@
     private boolean mWasHomeEnabled; // Was it enabled before action view expansion?
 
     private MenuBuilder mOptionsMenu;
+    private boolean mMenuPrepared;
     
     private ActionBarContextView mContextView;
 
@@ -164,7 +166,10 @@
 
     private final OnClickListener mUpClickListener = new OnClickListener() {
         public void onClick(View v) {
-            mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
+            if (mMenuPrepared) {
+                // Only invoke the window callback if the options menu has been initialized.
+                mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
+            }
         }
     };
 
@@ -285,6 +290,10 @@
             initTitle();
         }
 
+        if (mHomeDescriptionRes != 0) {
+            setHomeActionContentDescription(mHomeDescriptionRes);
+        }
+
         if (mTabScrollView != null && mIncludeTabs) {
             ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
             if (lp != null) {
@@ -402,6 +411,10 @@
         mCallback = callback;
     }
 
+    public void setMenuPrepared() {
+        mMenuPrepared = true;
+    }
+
     public void setMenu(Menu menu, MenuPresenter.Callback cb) {
         if (menu == mOptionsMenu) return;
 
@@ -582,14 +595,43 @@
             mUpGoerFive.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         } else {
             mUpGoerFive.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+            mUpGoerFive.setContentDescription(buildHomeContentDescription());
+        }
+    }
+
+    /**
+     * Compose a content description for the Home/Up affordance.
+     *
+     * <p>As this encompasses the icon/logo, title and subtitle all in one, we need
+     * a description for the whole wad of stuff that can be localized properly.</p>
+     */
+    private CharSequence buildHomeContentDescription() {
+        final CharSequence homeDesc;
+        if (mHomeDescription != null) {
+            homeDesc = mHomeDescription;
+        } else {
             if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
-                mUpGoerFive.setContentDescription(mContext.getResources().getText(
-                        R.string.action_bar_up_description));
+                homeDesc = mContext.getResources().getText(R.string.action_bar_up_description);
             } else {
-                mUpGoerFive.setContentDescription(mContext.getResources().getText(
-                        R.string.action_bar_home_description));
+                homeDesc = mContext.getResources().getText(R.string.action_bar_home_description);
             }
         }
+
+        final CharSequence title = getTitle();
+        final CharSequence subtitle = getSubtitle();
+        if (!TextUtils.isEmpty(title)) {
+            final String result;
+            if (!TextUtils.isEmpty(subtitle)) {
+                result = getResources().getString(
+                        R.string.action_bar_home_subtitle_description_format,
+                        title, subtitle, homeDesc);
+            } else {
+                result = getResources().getString(R.string.action_bar_home_description_format,
+                        title, homeDesc);
+            }
+            return result;
+        }
+        return homeDesc;
     }
 
     public void setDisplayOptions(int options) {
@@ -835,6 +877,8 @@
                 (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) {
             // Don't show while in expanded mode or with empty text
             mTitleLayout.setVisibility(GONE);
+        } else {
+            mTitleLayout.setVisibility(VISIBLE);
         }
     }
 
@@ -1296,6 +1340,23 @@
         }
     }
 
+    public void setHomeAsUpIndicator(Drawable indicator) {
+        mHomeLayout.setUpIndicator(indicator);
+    }
+
+    public void setHomeAsUpIndicator(int resId) {
+        mHomeLayout.setUpIndicator(resId);
+    }
+
+    public void setHomeActionContentDescription(CharSequence description) {
+        mHomeDescription = description;
+    }
+
+    public void setHomeActionContentDescription(int resId) {
+        mHomeDescriptionRes = resId;
+        mHomeDescription = getResources().getText(resId);
+    }
+
     static class SavedState extends BaseSavedState {
         int expandedMenuItemId;
         boolean isOverflowOpen;
@@ -1330,9 +1391,11 @@
     }
 
     private static class HomeView extends FrameLayout {
-        private View mUpView;
+        private ImageView mUpView;
         private ImageView mIconView;
         private int mUpWidth;
+        private int mUpIndicatorRes;
+        private Drawable mDefaultUpIndicator;
 
         private static final long DEFAULT_TRANSITION_DURATION = 150;
 
@@ -1357,6 +1420,25 @@
             mIconView.setImageDrawable(icon);
         }
 
+        public void setUpIndicator(Drawable d) {
+            mUpView.setImageDrawable(d != null ? d : mDefaultUpIndicator);
+            mUpIndicatorRes = 0;
+        }
+
+        public void setUpIndicator(int resId) {
+            mUpIndicatorRes = resId;
+            mUpView.setImageDrawable(resId != 0 ? getResources().getDrawable(resId) : null);
+        }
+
+        @Override
+        protected void onConfigurationChanged(Configuration newConfig) {
+            super.onConfigurationChanged(newConfig);
+            if (mUpIndicatorRes != 0) {
+                // Reload for config change
+                setUpIndicator(mUpIndicatorRes);
+            }
+        }
+
         @Override
         public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
             onPopulateAccessibilityEvent(event);
@@ -1380,8 +1462,9 @@
 
         @Override
         protected void onFinishInflate() {
-            mUpView = findViewById(com.android.internal.R.id.up);
+            mUpView = (ImageView) findViewById(com.android.internal.R.id.up);
             mIconView = (ImageView) findViewById(com.android.internal.R.id.home);
+            mDefaultUpIndicator = mUpView.getDrawable();
         }
 
         public int getStartOffset() {
@@ -1587,15 +1670,10 @@
                     mTitleLayout.setVisibility(VISIBLE);
                 }
             }
-            if (mTabScrollView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) {
-                mTabScrollView.setVisibility(VISIBLE);
-            }
-            if (mSpinner != null && mNavigationMode == ActionBar.NAVIGATION_MODE_LIST) {
-                mSpinner.setVisibility(VISIBLE);
-            }
-            if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
-                mCustomNavView.setVisibility(VISIBLE);
-            }
+            if (mTabScrollView != null) mTabScrollView.setVisibility(VISIBLE);
+            if (mSpinner != null) mSpinner.setVisibility(VISIBLE);
+            if (mCustomNavView != null) mCustomNavView.setVisibility(VISIBLE);
+
             mExpandedHomeLayout.setIcon(null);
             mCurrentExpandedItem = null;
             setHomeButtonEnabled(mWasHomeEnabled); // Set by expandItemActionView above
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 7a76ab0..1b088b3 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -38,6 +38,7 @@
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.R;
+import com.android.internal.widget.LockPatternView.Cell;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -72,6 +73,12 @@
      */
     private static final int MILLIS_PER_CIRCLE_ANIMATING = 700;
 
+    /**
+     * This can be used to avoid updating the display for very small motions or noisy panels.
+     * It didn't seem to have much impact on the devices tested, so currently set to 0.
+     */
+    private static final float DRAG_THRESHHOLD = 0.0f;
+
     private OnPatternListener mOnPatternListener;
     private ArrayList<Cell> mPattern = new ArrayList<Cell>(9);
 
@@ -674,10 +681,11 @@
         // Handle all recent motion events so we don't skip any cells even when the device
         // is busy...
         final int historySize = event.getHistorySize();
+        Rect invalidateRect = mInvalidate;
+        boolean invalidateNow = false;
         for (int i = 0; i < historySize + 1; i++) {
             final float x = i < historySize ? event.getHistoricalX(i) : event.getX();
             final float y = i < historySize ? event.getHistoricalY(i) : event.getY();
-            final int patternSizePreHitDetect = mPattern.size();
             Cell hitCell = detectAndAddHit(x, y);
             final int patternSize = mPattern.size();
             if (hitCell != null && patternSize == 1) {
@@ -687,113 +695,47 @@
             // note current x and y for rubber banding of in progress patterns
             final float dx = Math.abs(x - mInProgressX);
             final float dy = Math.abs(y - mInProgressY);
-            if (dx + dy > mSquareWidth * 0.01f) {
-                float oldX = mInProgressX;
-                float oldY = mInProgressY;
-
-                mInProgressX = x;
-                mInProgressY = y;
-
-                if (mPatternInProgress && patternSize > 0) {
-                    final ArrayList<Cell> pattern = mPattern;
-                    final float radius = mSquareWidth * mDiameterFactor * 0.5f;
-
-                    final Cell lastCell = pattern.get(patternSize - 1);
-
-                    float startX = getCenterXForColumn(lastCell.column);
-                    float startY = getCenterYForRow(lastCell.row);
-
-                    float left;
-                    float top;
-                    float right;
-                    float bottom;
-
-                    final Rect invalidateRect = mInvalidate;
-
-                    if (startX < x) {
-                        left = startX;
-                        right = x;
-                    } else {
-                        left = x;
-                        right = startX;
-                    }
-
-                    if (startY < y) {
-                        top = startY;
-                        bottom = y;
-                    } else {
-                        top = y;
-                        bottom = startY;
-                    }
-
-                    // Invalidate between the pattern's last cell and the current location
-                    invalidateRect.set((int) (left - radius), (int) (top - radius),
-                            (int) (right + radius), (int) (bottom + radius));
-
-                    if (startX < oldX) {
-                        left = startX;
-                        right = oldX;
-                    } else {
-                        left = oldX;
-                        right = startX;
-                    }
-
-                    if (startY < oldY) {
-                        top = startY;
-                        bottom = oldY;
-                    } else {
-                        top = oldY;
-                        bottom = startY;
-                    }
-
-                    // Invalidate between the pattern's last cell and the previous location
-                    invalidateRect.union((int) (left - radius), (int) (top - radius),
-                            (int) (right + radius), (int) (bottom + radius));
-
-                    // Invalidate between the pattern's new cell and the pattern's previous cell
-                    if (hitCell != null) {
-                        startX = getCenterXForColumn(hitCell.column);
-                        startY = getCenterYForRow(hitCell.row);
-
-                        if (patternSize >= 2) {
-                            // (re-using hitcell for old cell)
-                            hitCell = pattern.get(patternSize - 1 - (patternSize - patternSizePreHitDetect));
-                            oldX = getCenterXForColumn(hitCell.column);
-                            oldY = getCenterYForRow(hitCell.row);
-
-                            if (startX < oldX) {
-                                left = startX;
-                                right = oldX;
-                            } else {
-                                left = oldX;
-                                right = startX;
-                            }
-
-                            if (startY < oldY) {
-                                top = startY;
-                                bottom = oldY;
-                            } else {
-                                top = oldY;
-                                bottom = startY;
-                            }
-                        } else {
-                            left = right = startX;
-                            top = bottom = startY;
-                        }
-
-                        final float widthOffset = mSquareWidth / 2f;
-                        final float heightOffset = mSquareHeight / 2f;
-
-                        invalidateRect.set((int) (left - widthOffset),
-                                (int) (top - heightOffset), (int) (right + widthOffset),
-                                (int) (bottom + heightOffset));
-                    }
-
-                    invalidate(invalidateRect);
-                } else {
-                    invalidate();
-                }
+            if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
+                invalidateNow = true;
             }
+
+            if (mPatternInProgress && patternSize > 0) {
+                final ArrayList<Cell> pattern = mPattern;
+                final Cell lastCell = pattern.get(patternSize - 1);
+                float startX = getCenterXForColumn(lastCell.column);
+                float startY = getCenterYForRow(lastCell.row);
+
+                // Adjust for current position. Radius accounts for line width.
+                final float radius = (mSquareWidth * mDiameterFactor * 0.5f);
+                float left = Math.min(startX, x) - radius;
+                float right = Math.max(startX, x) + radius;
+                float top = Math.min(startY, y) - radius;
+                float bottom = Math.max(startY, y) + radius;
+
+                // Invalidate between the pattern's new cell and the pattern's previous cell
+                if (hitCell != null && patternSize >= 2) {
+                    final float width = mSquareWidth * 0.5f;
+                    final float height = mSquareHeight * 0.5f;
+                    final float x2 = getCenterXForColumn(hitCell.column);
+                    final float y2 = getCenterYForRow(hitCell.row);
+                    left = Math.min(x2, left - width);
+                    right = Math.max(x2, right + width);
+                    top = Math.min(y2, top - height);
+                    bottom = Math.max(y2, bottom + height);
+                }
+
+                // Invalidate between the pattern's last cell and the previous location
+                invalidateRect.union(Math.round(left), Math.round(top),
+                        Math.round(right), Math.round(bottom));
+            }
+        }
+        mInProgressX = event.getX();
+        mInProgressY = event.getY();
+
+        // To save updates, we only invalidate if the user moved beyond a certain amount.
+        if (invalidateNow) {
+            invalidate(invalidateRect);
+            invalidateRect.setEmpty();
         }
     }
 
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index b620568..04931e7 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -179,6 +179,9 @@
                 animateToTab(position);
             }
         }
+        if (mTabSpinner != null && position >= 0) {
+            mTabSpinner.setSelection(position);
+        }
     }
 
     public void setContentHeight(int contentHeight) {
diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java
index c33f038..ca797eb 100644
--- a/core/java/com/android/internal/widget/TransportControlView.java
+++ b/core/java/com/android/internal/widget/TransportControlView.java
@@ -143,7 +143,8 @@
             mLocalHandler = new WeakReference<Handler>(handler);
         }
 
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
@@ -157,7 +158,7 @@
             }
         }
 
-        public void setTransportControlFlags(int generationId, int flags) {
+        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1e27be8..3e5586e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -44,6 +44,7 @@
 	android_view_InputChannel.cpp \
 	android_view_InputDevice.cpp \
 	android_view_InputEventReceiver.cpp \
+	android_view_InputEventSender.cpp \
 	android_view_KeyEvent.cpp \
 	android_view_KeyCharacterMap.cpp \
 	android_view_HardwareRenderer.cpp \
@@ -178,6 +179,7 @@
 	libandroidfw \
 	libexpat \
 	libnativehelper \
+	liblog \
 	libcutils \
 	libutils \
 	libbinder \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 86d3cb6..1300d01 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -163,6 +163,7 @@
 extern int register_android_view_InputChannel(JNIEnv* env);
 extern int register_android_view_InputDevice(JNIEnv* env);
 extern int register_android_view_InputEventReceiver(JNIEnv* env);
+extern int register_android_view_InputEventSender(JNIEnv* env);
 extern int register_android_view_KeyCharacterMap(JNIEnv *env);
 extern int register_android_view_KeyEvent(JNIEnv* env);
 extern int register_android_view_MotionEvent(JNIEnv* env);
@@ -1195,6 +1196,7 @@
     REG_JNI(register_android_app_NativeActivity),
     REG_JNI(register_android_view_InputChannel),
     REG_JNI(register_android_view_InputEventReceiver),
+    REG_JNI(register_android_view_InputEventSender),
     REG_JNI(register_android_view_KeyEvent),
     REG_JNI(register_android_view_MotionEvent),
     REG_JNI(register_android_view_PointerIcon),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 6640555..11c7053 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -77,7 +77,14 @@
     }
 
     static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
-        return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
+        if (bitmap) {
+            return new SkCanvas(*bitmap);
+        } else {
+            // Create an empty bitmap device to prevent callers from crashing
+            // if they attempt to draw into this canvas.
+            SkBitmap emptyBitmap;
+            return new SkCanvas(emptyBitmap);
+        }
     }
     
     static void copyCanvasState(JNIEnv* env, jobject clazz,
@@ -752,37 +759,37 @@
     }
 
 
-    static void drawText___CIIFFPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+    static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
-                                      jfloat x, jfloat y, SkPaint* paint) {
+                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, paint);
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
-    static void drawText__StringIIFFPaint(JNIEnv* env, jobject,
+    static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
                                           SkCanvas* canvas, jstring text,
                                           int start, int end,
-                                          jfloat x, jfloat y, SkPaint* paint) {
+                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, paint);
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
         env->ReleaseStringChars(text, textArray);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
-            jfloat x, jfloat y, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
 
         jint count = end - start;
-        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, paint);
+        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int count, int contextCount,
-            jfloat x, jfloat y, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-                textArray, start, count, contextCount);
+                textArray, start, count, contextCount, flags);
         if (value == NULL) {
             return;
         }
@@ -793,7 +800,7 @@
             x -= value->getTotalAdvance();
         }
         paint->setTextAlign(SkPaint::kLeft_Align);
-        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, paint);
+        doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
         doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
         paint->setTextAlign(align);
     }
@@ -835,8 +842,14 @@
     }
 }
 
+    static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
+            jfloat x, jfloat y, int flags, SkPaint* paint) {
+        // Beware: this needs Glyph encoding (already done on the Paint constructor)
+        canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
+    }
+
     static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
-            int index, int count, jfloat x, jfloat y, SkPaint* paint) {
+            int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
         SkPoint* posPtr = new SkPoint[count];
         for (int indx = 0; indx < count; indx++) {
             posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
@@ -846,27 +859,27 @@
         delete[] posPtr;
     }
 
-    static void drawTextRun___CIIIIFFPaint(
+    static void drawTextRun___CIIIIFFIPaint(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
-                count, contextCount, x, y, paint);
+                count, contextCount, x, y, dirFlags, paint);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
-    static void drawTextRun__StringIIIIFFPaint(
+    static void drawTextRun__StringIIIIFFIPaint(
         JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start,
         jint end, jint contextStart, jint contextEnd,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, jint dirFlags, SkPaint* paint) {
 
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
-                count, contextCount, x, y, paint);
+                count, contextCount, x, y, dirFlags, paint);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -929,19 +942,21 @@
 
     static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jcharArray text, int index, int count,
-            SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+            SkPath* path, jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
 
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        TextLayout::drawTextOnPath(paint, textArray + index, count, hOffset, vOffset, path, canvas);
+        TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas);
         env->ReleaseCharArrayElements(text, textArray, 0);
     }
 
     static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject,
             SkCanvas* canvas, jstring text, SkPath* path,
-            jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+            jfloat hOffset, jfloat vOffset, jint bidiFlags, SkPaint* paint) {
         const jchar* text_ = env->GetStringChars(text, NULL);
         int count = env->GetStringLength(text);
-        TextLayout::drawTextOnPath(paint, text_, count, hOffset, vOffset, path, canvas);
+        TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset,
+                                   path, canvas);
         env->ReleaseStringChars(text, text_);
     }
 
@@ -1051,21 +1066,21 @@
         (void*)SkCanvasGlue::drawBitmapMesh},
     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
         (void*)SkCanvasGlue::drawVertices},
-    {"native_drawText","(I[CIIFFI)V",
-        (void*) SkCanvasGlue::drawText___CIIFFPaint},
-    {"native_drawText","(ILjava/lang/String;IIFFI)V",
-        (void*) SkCanvasGlue::drawText__StringIIFFPaint},
-    {"native_drawTextRun","(I[CIIIIFFI)V",
-        (void*) SkCanvasGlue::drawTextRun___CIIIIFFPaint},
-    {"native_drawTextRun","(ILjava/lang/String;IIIIFFI)V",
-        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFPaint},
+    {"native_drawText","(I[CIIFFII)V",
+        (void*) SkCanvasGlue::drawText___CIIFFIPaint},
+    {"native_drawText","(ILjava/lang/String;IIFFII)V",
+        (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
+    {"native_drawTextRun","(I[CIIIIFFII)V",
+        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
+    {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
+        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
     {"native_drawPosText","(I[CII[FI)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(ILjava/lang/String;[FI)V",
         (void*) SkCanvasGlue::drawPosText__String_FPaint},
-    {"native_drawTextOnPath","(I[CIIIFFI)V",
+    {"native_drawTextOnPath","(I[CIIIFFII)V",
         (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint},
-    {"native_drawTextOnPath","(ILjava/lang/String;IFFI)V",
+    {"native_drawTextOnPath","(ILjava/lang/String;IFFII)V",
         (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint},
     {"native_drawPicture", "(II)V", (void*) SkCanvasGlue::drawPicture},
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 07f55e0..5454c08 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -383,7 +383,8 @@
         return descent - ascent + leading;
     }
 
-    static jfloat measureText_CII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count) {
+    static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, int index, int count,
+            jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -401,13 +402,14 @@
         jfloat result = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, index, count, textLength,
-                NULL /* dont need all advances */, &result);
+                bidiFlags, NULL /* dont need all advances */, &result);
 
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
     }
 
-    static jfloat measureText_StringII(JNIEnv* env, jobject jpaint, jstring text, int start, int end) {
+    static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, int start, int end,
+            jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -426,13 +428,13 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, start, count, textLength,
-                NULL /* dont need all advances */, &width);
+                bidiFlags, NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
     }
 
-    static jfloat measureText_String(JNIEnv* env, jobject jpaint, jstring text) {
+    static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -446,13 +448,14 @@
         jfloat width = 0;
 
         TextLayout::getTextRunAdvances(paint, textArray, 0, textLength, textLength,
-                NULL /* dont need all advances */, &width);
+                bidiFlags, NULL /* dont need all advances */, &width);
 
         env->ReleaseStringChars(text, textArray);
         return width;
     }
 
-    static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths) {
+    static int dotextwidths(JNIEnv* env, SkPaint* paint, const jchar text[], int count, jfloatArray widths,
+            jint bidiFlags) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -473,29 +476,70 @@
         jfloat* widthsArray = autoWidths.ptr();
 
         TextLayout::getTextRunAdvances(paint, text, 0, count, count,
-                widthsArray, NULL /* dont need totalAdvance */);
+                bidiFlags, widthsArray, NULL /* dont need totalAdvance */);
 
         return count;
     }
 
-    static int getTextWidths___CII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text, int index, int count, jfloatArray widths) {
+    static int getTextWidths___CIII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text,
+            int index, int count, jint bidiFlags, jfloatArray widths) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        count = dotextwidths(env, paint, textArray + index, count, widths);
+        count = dotextwidths(env, paint, textArray + index, count, widths, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
                                       JNI_ABORT);
         return count;
     }
 
-    static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
-            int start, int end, jfloatArray widths) {
+    static int getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
+            int start, int end, jint bidiFlags, jfloatArray widths) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        int count = dotextwidths(env, paint, textArray + start, end - start, widths);
+        int count = dotextwidths(env, paint, textArray + start, end - start, widths, bidiFlags);
+        env->ReleaseStringChars(text, textArray);
+        return count;
+    }
+
+    static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
+            jint contextCount, jint flags, jcharArray glyphs) {
+        NPE_CHECK_RETURN_ZERO(env, paint);
+        NPE_CHECK_RETURN_ZERO(env, text);
+
+        if ((start | count | contextCount) < 0 || contextCount < count || !glyphs) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+        if (count == 0) {
+            return 0;
+        }
+        size_t glypthsLength = env->GetArrayLength(glyphs);
+        if ((size_t)count > glypthsLength) {
+            doThrowAIOOBE(env);
+            return 0;
+        }
+
+        jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
+
+        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+                text, start, count, contextCount, flags);
+        const jchar* shapedGlyphs = value->getGlyphs();
+        size_t glyphsCount = value->getGlyphsCount();
+        memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
+
+        env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
+        return glyphsCount;
+    }
+
+    static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+            jcharArray glyphs) {
+        const jchar* textArray = env->GetStringChars(text, NULL);
+        int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
+                end - start, contextEnd - contextStart, flags, glyphs);
         env->ReleaseStringChars(text, textArray);
         return count;
     }
 
     static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
-                                    jint start, jint count, jint contextCount,
+                                    jint start, jint count, jint contextCount, jint flags,
                                     jfloatArray advances, jint advancesIndex) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
@@ -517,7 +561,7 @@
         jfloat advancesArray[count];
         jfloat totalAdvance = 0;
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount,
+        TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
                                        advancesArray, &totalAdvance);
 
         if (advances != NULL) {
@@ -526,32 +570,32 @@
         return totalAdvance;
     }
 
-    static float getTextRunAdvances___CIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static float getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
-            jfloatArray advances, jint advancesIndex) {
+            jint flags, jfloatArray advances, jint advancesIndex) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
         jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
-                index - contextIndex, count, contextCount, advances, advancesIndex);
+                index - contextIndex, count, contextCount, flags, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
-    static float getTextRunAdvances__StringIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd,
+    static float getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
             jfloatArray advances, jint advancesIndex) {
         const jchar* textArray = env->GetStringChars(text, NULL);
         jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
-                start - contextStart, end - start, contextEnd - contextStart,
+                start - contextStart, end - start, contextEnd - contextStart, flags,
                 advances, advancesIndex);
         env->ReleaseStringChars(text, textArray);
         return result;
     }
 
     static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
-            jint count, jint offset, jint opt) {
+            jint count, jint flags, jint offset, jint opt) {
         jfloat scalarArray[count];
 
-        TextLayout::getTextRunAdvances(paint, text, start, count, start + count,
+        TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags,
                 scalarArray, NULL /* dont need totalAdvance */);
 
         jint pos = offset - start;
@@ -592,39 +636,39 @@
     }
 
     static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, SkPaint* paint, jcharArray text,
-            jint contextStart, jint contextCount, jint offset, jint cursorOpt) {
+            jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount,
+        jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags,
                 offset, cursorOpt);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
     static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
-            jint contextStart, jint contextEnd, jint offset, jint cursorOpt) {
+            jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) {
         const jchar* textArray = env->GetStringChars(text, NULL);
         jint result = doTextRunCursor(env, paint, textArray, contextStart,
-                contextEnd - contextStart, offset, cursorOpt);
+                contextEnd - contextStart, flags, offset, cursorOpt);
         env->ReleaseStringChars(text, textArray);
         return result;
     }
 
     static void getTextPath(JNIEnv* env, SkPaint* paint, const jchar* text, jint count,
-                            jfloat x, jfloat y, SkPath *path) {
-        TextLayout::getTextPath(paint, text, count, x, y, path);
+                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+        TextLayout::getTextPath(paint, text, count, bidiFlags, x, y, path);
     }
 
-    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static void getTextPath___C(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
             jcharArray text, int index, int count, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        getTextPath(env, paint, textArray + index, count, x, y, path);
+        getTextPath(env, paint, textArray + index, count, bidiFlags, x, y, path);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
     }
 
-    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint,
+    static void getTextPath__String(JNIEnv* env, jobject clazz, SkPaint* paint, jint bidiFlags,
             jstring text, int start, int end, jfloat x, jfloat y, SkPath* path) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        getTextPath(env, paint, textArray + start, end - start, x, y, path);
+        getTextPath(env, paint, textArray + start, end - start, bidiFlags, x, y, path);
         env->ReleaseStringChars(text, textArray);
     }
 
@@ -645,10 +689,10 @@
     }
 
     static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
-                         int count, float maxWidth, jfloatArray jmeasured,
+                         int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count);
+                text, 0, count, count, bidiFlags);
         if (value == NULL) {
             return 0;
         }
@@ -666,7 +710,7 @@
     }
 
     static int breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
-            int index, int count, float maxWidth, jfloatArray jmeasuredWidth) {
+            int index, int count, float maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
@@ -687,14 +731,14 @@
         SkPaint*     paint = GraphicsJNI::getNativePaint(env, jpaint);
         const jchar* text = env->GetCharArrayElements(jtext, NULL);
         count = breakText(env, *paint, text + index, count, maxWidth,
-                          jmeasuredWidth, tbd);
+                          bidiFlags, jmeasuredWidth, tbd);
         env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
                                       JNI_ABORT);
         return count;
     }
 
     static int breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
-                bool forwards, float maxWidth, jfloatArray jmeasuredWidth) {
+                bool forwards, float maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
         NPE_CHECK_RETURN_ZERO(env, jpaint);
         NPE_CHECK_RETURN_ZERO(env, jtext);
 
@@ -705,22 +749,20 @@
         SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
         int count = env->GetStringLength(jtext);
         const jchar* text = env->GetStringChars(jtext, NULL);
-        count = breakText(env, *paint, text, count, maxWidth,
-                          jmeasuredWidth, tbd);
+        count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
         env->ReleaseStringChars(jtext, text);
         return count;
     }
 
     static void doTextBounds(JNIEnv* env, const jchar* text, int count,
-                             jobject bounds, const SkPaint& paint)
-    {
+                             jobject bounds, const SkPaint& paint, jint bidiFlags) {
         SkRect  r;
         r.set(0,0,0,0);
 
         SkIRect ir;
 
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
-                text, 0, count, count);
+                text, 0, count, count, bidiFlags);
         if (value == NULL) {
             return;
         }
@@ -730,18 +772,16 @@
     }
 
     static void getStringBounds(JNIEnv* env, jobject, const SkPaint* paint,
-                                jstring text, int start, int end, jobject bounds)
-    {
+                                jstring text, int start, int end, jint bidiFlags, jobject bounds) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        doTextBounds(env, textArray + start, end - start, bounds, *paint);
+        doTextBounds(env, textArray + start, end - start, bounds, *paint, bidiFlags);
         env->ReleaseStringChars(text, textArray);
     }
 
     static void getCharArrayBounds(JNIEnv* env, jobject, const SkPaint* paint,
-                        jcharArray text, int index, int count, jobject bounds)
-    {
+                        jcharArray text, int index, int count, jint bidiFlags, jobject bounds) {
         const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        doTextBounds(env, textArray + index, count, bounds, *paint);
+        doTextBounds(env, textArray + index, count, bounds, *paint, bidiFlags);
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
                                       JNI_ABORT);
     }
@@ -801,25 +841,29 @@
     {"descent","()F", (void*) SkPaintGlue::descent},
     {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)SkPaintGlue::getFontMetrics},
     {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)SkPaintGlue::getFontMetricsInt},
-    {"native_measureText","([CII)F", (void*) SkPaintGlue::measureText_CII},
-    {"native_measureText","(Ljava/lang/String;)F", (void*) SkPaintGlue::measureText_String},
-    {"native_measureText","(Ljava/lang/String;II)F", (void*) SkPaintGlue::measureText_StringII},
-    {"native_breakText","([CIIF[F)I", (void*) SkPaintGlue::breakTextC},
-    {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
-    {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
-    {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
-    {"native_getTextRunAdvances","(I[CIIII[FI)F",
-        (void*) SkPaintGlue::getTextRunAdvances___CIIII_FI},
-    {"native_getTextRunAdvances","(ILjava/lang/String;IIII[FI)F",
-        (void*) SkPaintGlue::getTextRunAdvances__StringIIII_FI},
-    {"native_getTextRunCursor", "(I[CIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
-    {"native_getTextRunCursor", "(ILjava/lang/String;IIII)I",
+    {"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII},
+    {"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI},
+    {"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
+    {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
+    {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
+    {"native_getTextWidths","(I[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
+    {"native_getTextWidths","(ILjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
+    {"native_getTextRunAdvances","(I[CIIIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
+    {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+
+
+    {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
+        (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
+    {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
+    {"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
         (void*) SkPaintGlue::getTextRunCursor__String},
-    {"native_getTextPath","(I[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
-    {"native_getTextPath","(ILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
-    {"nativeGetStringBounds", "(ILjava/lang/String;IILandroid/graphics/Rect;)V",
+    {"native_getTextPath","(II[CIIFFI)V", (void*) SkPaintGlue::getTextPath___C},
+    {"native_getTextPath","(IILjava/lang/String;IIFFI)V", (void*) SkPaintGlue::getTextPath__String},
+    {"nativeGetStringBounds", "(ILjava/lang/String;IIILandroid/graphics/Rect;)V",
                                         (void*) SkPaintGlue::getStringBounds },
-    {"nativeGetCharArrayBounds", "(I[CIILandroid/graphics/Rect;)V",
+    {"nativeGetCharArrayBounds", "(I[CIIILandroid/graphics/Rect;)V",
                                     (void*) SkPaintGlue::getCharArrayBounds },
     {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
 };
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 296d9b2..753f5dc 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -53,10 +53,10 @@
     GLConsumer* const p =
         (GLConsumer*)env->GetIntField(thiz, fields.surfaceTexture);
     if (surfaceTexture.get()) {
-        surfaceTexture->incStrong(thiz);
+        surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture);
     }
     if (p) {
-        p->decStrong(thiz);
+        p->decStrong((void*)SurfaceTexture_setSurfaceTexture);
     }
     env->SetIntField(thiz, fields.surfaceTexture, (int)surfaceTexture.get());
 }
@@ -68,10 +68,10 @@
         (GLConsumer::FrameAvailableListener*)
             env->GetIntField(thiz, fields.frameAvailableListener);
     if (listener.get()) {
-        listener->incStrong(thiz);
+        listener->incStrong((void*)SurfaceTexture_setSurfaceTexture);
     }
     if (p) {
-        p->decStrong(thiz);
+        p->decStrong((void*)SurfaceTexture_setSurfaceTexture);
     }
     env->SetIntField(thiz, fields.frameAvailableListener, (int)listener.get());
 }
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index b77236c..34dc3e8 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -28,13 +28,33 @@
 
 namespace android {
 
+// Returns true if we might need layout.  If bidiFlags force LTR, assume no layout, if
+// bidiFlags indicate there probably is RTL, assume we do, otherwise scan the text
+// looking for a character >= the first RTL character in unicode and assume we do if
+// we find one.
+bool TextLayout::needsLayout(const jchar* text, jint len, jint bidiFlags) {
+    if (bidiFlags == kBidi_Force_LTR) {
+        return false;
+    }
+    if ((bidiFlags == kBidi_RTL) || (bidiFlags == kBidi_Default_RTL) ||
+            bidiFlags == kBidi_Force_RTL) {
+        return true;
+    }
+    for (int i = 0; i < len; ++i) {
+        if (text[i] >= UNICODE_FIRST_RTL_CHAR) {
+            return true;
+        }
+    }
+    return false;
+}
+
 // Draws or gets the path of a paragraph of text on a single line, running bidi and shaping.
 // This will draw if canvas is not null, otherwise path must be non-null and it will create
 // a path representing the text that would have been drawn.
 void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
-                            jfloat x, jfloat y, SkPath *path) {
+                            jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, len, len);
+            text, 0, len, len, bidiFlags);
     if (value == NULL) {
         return ;
     }
@@ -45,10 +65,10 @@
 }
 
 void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                    jint count, jint contextCount,
+                                    jint count, jint contextCount, jint dirFlags,
                                     jfloat* resultAdvances, jfloat* resultTotalAdvance) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            chars, start, count, contextCount);
+            chars, start, count, contextCount, dirFlags);
     if (value == NULL) {
         return ;
     }
@@ -61,19 +81,20 @@
 }
 
 void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
-                             jfloat x, jfloat y, SkPath *path) {
-    handleText(paint, text, len, x, y, path);
+                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
+    handleText(paint, text, len, bidiFlags, x, y, path);
 }
 
+
 void TextLayout::drawTextOnPath(SkPaint* paint, const jchar* text, int count,
-                                jfloat hOffset, jfloat vOffset,
+                                int bidiFlags, jfloat hOffset, jfloat vOffset,
                                 SkPath* path, SkCanvas* canvas) {
 
     SkScalar h_ = SkFloatToScalar(hOffset);
     SkScalar v_ = SkFloatToScalar(vOffset);
 
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, bidiFlags);
     if (value == NULL) {
         return;
     }
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index fa388c8..d58c692 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -42,6 +42,17 @@
 #define USE_TEXT_LAYOUT_CACHE 1
 
 enum {
+    kBidi_LTR = 0,
+    kBidi_RTL = 1,
+    kBidi_Default_LTR = 2,
+    kBidi_Default_RTL = 3,
+    kBidi_Force_LTR = 4,
+    kBidi_Force_RTL = 5,
+
+    kBidi_Mask = 0x7
+};
+
+enum {
     kDirection_LTR = 0,
     kDirection_RTL = 1,
 
@@ -52,18 +63,20 @@
 public:
 
     static void getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
-                                   jint count, jint contextCount,
+                                   jint count, jint contextCount, jint dirFlags,
                                    jfloat* resultAdvances, jfloat* resultTotalAdvance);
 
     static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
-                            jfloat x, jfloat y, SkPath* path);
+                            jint bidiFlags, jfloat x, jfloat y, SkPath* path);
 
     static void drawTextOnPath(SkPaint* paint, const jchar* text, jsize len,
-                               jfloat hOffset, jfloat vOffset,
+                               int bidiFlags, jfloat hOffset, jfloat vOffset,
                                SkPath* path, SkCanvas* canvas);
 
 private:
+    static bool needsLayout(const jchar* text, jint len, jint bidiFlags);
+
     static void handleText(SkPaint* paint, const jchar* text, jsize len,
-                           jfloat x, jfloat y, SkPath* path);
+                           int bidiFlags, jfloat x, jfloat y, SkPath* path);
 };
 } // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 1a8612e..1ace23e 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -87,7 +87,7 @@
  * Caching
  */
 sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
-            const jchar* text, jint start, jint count, jint contextCount) {
+            const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
     AutoMutex _l(mLock);
     nsecs_t startTime = 0;
     if (mDebugEnabled) {
@@ -95,7 +95,7 @@
     }
 
     // Create the key
-    TextLayoutCacheKey key(paint, text, start, count, contextCount);
+    TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
 
     // Get value from cache if possible
     sp<TextLayoutValue> value = mCache.get(key);
@@ -111,7 +111,7 @@
         // Compute advances and store them
         mShaper->computeValues(value.get(), paint,
                 reinterpret_cast<const UChar*>(key.getText()), start, count,
-                size_t(contextCount));
+                size_t(contextCount), int(dirFlags));
 
         if (mDebugEnabled) {
             value->setElapsedTime(systemTime(SYSTEM_TIME_MONOTONIC) - startTime);
@@ -218,13 +218,14 @@
  * TextLayoutCacheKey
  */
 TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
-        typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
+        dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
         hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
-        size_t start, size_t count, size_t contextCount) :
-            start(start), count(count), contextCount(contextCount) {
+        size_t start, size_t count, size_t contextCount, int dirFlags) :
+            start(start), count(count), contextCount(contextCount),
+            dirFlags(dirFlags) {
     textCopy.setTo(text, contextCount);
     typeface = paint->getTypeface();
     textSize = paint->getTextSize();
@@ -241,6 +242,7 @@
         start(other.start),
         count(other.count),
         contextCount(other.contextCount),
+        dirFlags(other.dirFlags),
         typeface(other.typeface),
         textSize(other.textSize),
         textSkewX(other.textSkewX),
@@ -279,6 +281,9 @@
     deltaInt = lhs.hinting - rhs.hinting;
     if (deltaInt != 0) return (deltaInt);
 
+    deltaInt = lhs.dirFlags - rhs.dirFlags;
+    if (deltaInt) return (deltaInt);
+
     deltaInt = lhs.variant - rhs.variant;
     if (deltaInt) return (deltaInt);
 
@@ -354,9 +359,9 @@
 }
 
 void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount) {
+        size_t start, size_t count, size_t contextCount, int dirFlags) {
 
-    computeValues(paint, chars, start, count, contextCount,
+    computeValues(paint, chars, start, count, contextCount, dirFlags,
             &value->mAdvances, &value->mTotalAdvance, &value->mGlyphs, &value->mPos);
 #if DEBUG_ADVANCES
     ALOGD("Advances - start = %d, count = %d, contextCount = %d, totalAdvance = %f", start, count,
@@ -365,7 +370,7 @@
 }
 
 void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
-        size_t start, size_t count, size_t contextCount,
+        size_t start, size_t count, size_t contextCount, int dirFlags,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
         *outTotalAdvance = 0;
@@ -373,94 +378,110 @@
             return;
         }
 
-        UBiDiLevel bidiReq = UBIDI_DEFAULT_LTR;
+        UBiDiLevel bidiReq = 0;
+        bool forceLTR = false;
+        bool forceRTL = false;
+
+        switch (dirFlags & kBidi_Mask) {
+            case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
+            case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
+            case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
+            case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
+            case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
+            case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
+        }
+
         bool useSingleRun = false;
-        bool isRTL = false;
-
-        UBiDi* bidi = ubidi_open();
-        if (bidi) {
-            UErrorCode status = U_ZERO_ERROR;
+        bool isRTL = forceRTL;
+        if (forceLTR || forceRTL) {
+            useSingleRun = true;
+        } else {
+            UBiDi* bidi = ubidi_open();
+            if (bidi) {
+                UErrorCode status = U_ZERO_ERROR;
 #if DEBUG_GLYPHS
-            ALOGD("******** ComputeValues -- start");
-            ALOGD("      -- string = '%s'", String8(chars + start, count).string());
-            ALOGD("      -- start = %d", start);
-            ALOGD("      -- count = %d", count);
-            ALOGD("      -- contextCount = %d", contextCount);
-            ALOGD("      -- bidiReq = %d", bidiReq);
+                ALOGD("******** ComputeValues -- start");
+                ALOGD("      -- string = '%s'", String8(chars + start, count).string());
+                ALOGD("      -- start = %d", start);
+                ALOGD("      -- count = %d", count);
+                ALOGD("      -- contextCount = %d", contextCount);
+                ALOGD("      -- bidiReq = %d", bidiReq);
 #endif
-            ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
-            if (U_SUCCESS(status)) {
-                int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
-                ssize_t rc = ubidi_countRuns(bidi, &status);
+                ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
+                if (U_SUCCESS(status)) {
+                    int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
+                    ssize_t rc = ubidi_countRuns(bidi, &status);
 #if DEBUG_GLYPHS
-                ALOGD("      -- paraDir = %d", paraDir);
-                ALOGD("      -- run-count = %d", int(rc));
+                    ALOGD("      -- dirFlags = %d", dirFlags);
+                    ALOGD("      -- paraDir = %d", paraDir);
+                    ALOGD("      -- run-count = %d", int(rc));
 #endif
-                if (U_SUCCESS(status) && rc == 1) {
-                    // Normal case: one run, status is ok
-                    isRTL = (paraDir == 1);
-                    useSingleRun = true;
-                } else if (!U_SUCCESS(status) || rc < 1) {
-                    ALOGW("Need to force to single run -- string = '%s',"
-                            " status = %d, rc = %d",
-                            String8(chars + start, count).string(), status, int(rc));
-                    isRTL = (paraDir == 1);
-                    useSingleRun = true;
-                } else {
-                    int32_t end = start + count;
-                    for (size_t i = 0; i < size_t(rc); ++i) {
-                        int32_t startRun = -1;
-                        int32_t lengthRun = -1;
-                        UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
+                    if (U_SUCCESS(status) && rc == 1) {
+                        // Normal case: one run, status is ok
+                        isRTL = (paraDir == 1);
+                        useSingleRun = true;
+                    } else if (!U_SUCCESS(status) || rc < 1) {
+                        ALOGW("Need to force to single run -- string = '%s',"
+                                " status = %d, rc = %d",
+                                String8(chars + start, count).string(), status, int(rc));
+                        isRTL = (paraDir == 1);
+                        useSingleRun = true;
+                    } else {
+                        int32_t end = start + count;
+                        for (size_t i = 0; i < size_t(rc); ++i) {
+                            int32_t startRun = -1;
+                            int32_t lengthRun = -1;
+                            UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
 
-                        if (startRun == -1 || lengthRun == -1) {
-                            // Something went wrong when getting the visual run, need to clear
-                            // already computed data before doing a single run pass
-                            ALOGW("Visual run is not valid");
-                            outGlyphs->clear();
-                            outAdvances->clear();
-                            outPos->clear();
-                            *outTotalAdvance = 0;
-                            isRTL = (paraDir == 1);
-                            useSingleRun = true;
-                            break;
-                        }
+                            if (startRun == -1 || lengthRun == -1) {
+                                // Something went wrong when getting the visual run, need to clear
+                                // already computed data before doing a single run pass
+                                ALOGW("Visual run is not valid");
+                                outGlyphs->clear();
+                                outAdvances->clear();
+                                outPos->clear();
+                                *outTotalAdvance = 0;
+                                isRTL = (paraDir == 1);
+                                useSingleRun = true;
+                                break;
+                            }
 
-                        if (startRun >= end) {
-                            continue;
-                        }
-                        int32_t endRun = startRun + lengthRun;
-                        if (endRun <= int32_t(start)) {
-                            continue;
-                        }
-                        if (startRun < int32_t(start)) {
-                            startRun = int32_t(start);
-                        }
-                        if (endRun > end) {
-                            endRun = end;
-                        }
+                            if (startRun >= end) {
+                                continue;
+                            }
+                            int32_t endRun = startRun + lengthRun;
+                            if (endRun <= int32_t(start)) {
+                                continue;
+                            }
+                            if (startRun < int32_t(start)) {
+                                startRun = int32_t(start);
+                            }
+                            if (endRun > end) {
+                                endRun = end;
+                            }
 
-                        lengthRun = endRun - startRun;
-                        isRTL = (runDir == UBIDI_RTL);
+                            lengthRun = endRun - startRun;
+                            isRTL = (runDir == UBIDI_RTL);
 #if DEBUG_GLYPHS
-                        ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
-                                i, startRun, lengthRun, isRTL);
+                            ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
+                                    i, startRun, lengthRun, isRTL);
 #endif
-                        computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
-                                outAdvances, outTotalAdvance, outGlyphs, outPos);
+                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
+                                    outAdvances, outTotalAdvance, outGlyphs, outPos);
 
+                        }
                     }
+                } else {
+                    ALOGW("Cannot set Para");
+                    useSingleRun = true;
+                    isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
                 }
+                ubidi_close(bidi);
             } else {
-                ALOGW("Cannot set Para");
+                ALOGW("Cannot ubidi_open()");
                 useSingleRun = true;
                 isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
             }
-            ubidi_close(bidi);
-        } else {
-            ALOGW("Cannot ubidi_open()");
-            useSingleRun = true;
-            isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
         }
 
         // Default single run case
@@ -897,11 +918,11 @@
 }
 
 sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
-        jint start, jint count, jint contextCount) {
+        jint start, jint count, jint contextCount, jint dirFlags) {
     sp<TextLayoutValue> value;
 #if USE_TEXT_LAYOUT_CACHE
     value = mTextLayoutCache->getValue(paint, text, start, count,
-            contextCount);
+            contextCount, dirFlags);
     if (value == NULL) {
         ALOGE("Cannot get TextLayoutCache value for text = '%s'",
                 String8(text + start, count).string());
@@ -909,7 +930,7 @@
 #else
     value = new TextLayoutValue(count);
     mShaper->computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(text), start, count, contextCount);
+            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
 #endif
     return value;
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 6858c0e..f9b9900 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -70,7 +70,7 @@
     TextLayoutCacheKey();
 
     TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
-            size_t contextCount);
+            size_t contextCount, int dirFlags);
 
     TextLayoutCacheKey(const TextLayoutCacheKey& other);
 
@@ -97,6 +97,7 @@
     size_t start;
     size_t count;
     size_t contextCount;
+    int dirFlags;
     SkTypeface* typeface;
     SkScalar textSize;
     SkScalar textSkewX;
@@ -180,7 +181,7 @@
     virtual ~TextLayoutShaper();
 
     void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount);
+            size_t start, size_t count, size_t contextCount, int dirFlags);
 
     void purgeCaches();
 
@@ -214,7 +215,7 @@
     size_t shapeFontRun(const SkPaint* paint);
 
     void computeValues(const SkPaint* paint, const UChar* chars,
-            size_t start, size_t count, size_t contextCount,
+            size_t start, size_t count, size_t contextCount, int dirFlags,
             Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
@@ -251,7 +252,7 @@
     void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
 
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount);
+            jint count, jint contextCount, jint dirFlags);
 
     /**
      * Clear the cache
@@ -303,7 +304,7 @@
      * the call. Be careful of this when doing optimization.
      **/
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
-            jint count, jint contextCount);
+            jint count, jint contextCount, jint dirFlags);
 
     void purgeCaches();
 
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index 42d408d..f5eaf94 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -23,20 +23,17 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include <utils/Log.h>
+#include <utils/String8.h>
 
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#if defined(__arm__)
-extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, 
-        size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
-        
-extern "C" void free_malloc_leak_info(uint8_t* info);
-#endif
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+                                     size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
 
-#define MAPS_FILE_SIZE 65 * 1024
+extern "C" void free_malloc_leak_info(uint8_t* info);
 
 struct Header {
     size_t mapSize;
@@ -48,96 +45,57 @@
 
 namespace android {
 
+static void ReadFile(const char* path, String8& s) {
+    int fd = open(path, O_RDONLY);
+    if (fd != -1) {
+        char bytes[1024];
+        ssize_t byteCount;
+        while ((byteCount = TEMP_FAILURE_RETRY(read(fd, bytes, sizeof(bytes)))) > 0) {
+            s.append(bytes, byteCount);
+        }
+        close(fd);
+    }
+}
+
 /*
- * Retrieve the native heap information and the info from /proc/<self>/maps,
+ * Retrieve the native heap information and the info from /proc/self/maps,
  * copy them into a byte[] with a "struct Header" that holds data offsets,
  * and return the array.
  */
-static jbyteArray getLeakInfo(JNIEnv *env, jobject clazz)
-{
-#if defined(__arm__)
-    // get the info in /proc/[pid]/map
+static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) {
     Header header;
     memset(&header, 0, sizeof(header));
 
-    pid_t pid = getpid();
-
-    char path[FILENAME_MAX];
-    sprintf(path, "/proc/%d/maps", pid);
-
-    struct stat sb;
-    int ret = stat(path, &sb);
-
-    uint8_t* mapsFile = NULL;
-    if (ret == 0) {
-        mapsFile = (uint8_t*)malloc(MAPS_FILE_SIZE);
-        int fd = open(path, O_RDONLY);
-    
-        if (mapsFile != NULL && fd != -1) {
-            int amount = 0;
-            do {
-                uint8_t* ptr = mapsFile + header.mapSize;
-                amount = read(fd, ptr, MAPS_FILE_SIZE);
-                if (amount <= 0) {
-                    if (errno != EINTR)
-                        break; 
-                    else
-                        continue;
-                }
-                header.mapSize += amount;
-            } while (header.mapSize < MAPS_FILE_SIZE);
-            
-            ALOGD("**** read %d bytes from '%s'", (int) header.mapSize, path);
-        }
-    }
+    String8 maps;
+    ReadFile("/proc/self/maps", maps);
+    header.mapSize = maps.size();
 
     uint8_t* allocBytes;
-    get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize, 
-            &header.totalMemory, &header.backtraceSize);
+    get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize,
+                         &header.totalMemory, &header.backtraceSize);
 
-    jbyte* bytes = NULL;
-    jbyte* ptr = NULL;
+    ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d",
+          header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
+
     jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize);
-    if (array == NULL) {
-        goto done;
+    if (array != NULL) {
+        env->SetByteArrayRegion(array, 0,
+                                sizeof(header), reinterpret_cast<jbyte*>(&header));
+        env->SetByteArrayRegion(array, sizeof(header),
+                                maps.size(), reinterpret_cast<const jbyte*>(maps.string()));
+        env->SetByteArrayRegion(array, sizeof(header) + maps.size(),
+                                header.allocSize, reinterpret_cast<jbyte*>(allocBytes));
     }
 
-    bytes = env->GetByteArrayElements(array, NULL);
-    ptr = bytes;
-
-//    ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d", 
-//            header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
-
-    memcpy(ptr, &header, sizeof(header));
-    ptr += sizeof(header);
-    
-    if (header.mapSize > 0 && mapsFile != NULL) {
-        memcpy(ptr, mapsFile, header.mapSize);
-        ptr += header.mapSize;
-    }
-    
-    memcpy(ptr, allocBytes, header.allocSize);
-    env->ReleaseByteArrayElements(array, bytes, 0);
-
-done:
-    if (mapsFile != NULL) {
-        free(mapsFile);
-    }
-    // free the info up!
     free_malloc_leak_info(allocBytes);
-
     return array;
-#else
-    return NULL;
-#endif
 }
 
 static JNINativeMethod method_table[] = {
-    { "getLeakInfo", "()[B", (void*)getLeakInfo },
+    { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo },
 };
 
-int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env)
-{
+int register_android_ddm_DdmHandleNativeHeap(JNIEnv* env) {
     return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table));
 }
 
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 362d9a4..686e4e3 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -496,7 +496,7 @@
     // We use a weak reference so the Camera object can be garbage collected.
     // The reference is only used as a proxy for callbacks.
     sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
-    context->incStrong(thiz);
+    context->incStrong((void*)android_hardware_Camera_native_setup);
     camera->setListener(context);
 
     // save context in opaque field
@@ -534,7 +534,7 @@
         }
 
         // remove context to prevent further Java access
-        context->decStrong(thiz);
+        context->decStrong((void*)android_hardware_Camera_native_setup);
     }
 }
 
@@ -544,13 +544,17 @@
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
     if (camera == 0) return;
 
+    sp<IGraphicBufferProducer> gbp;
     sp<Surface> surface;
     if (jSurface) {
         surface = android_view_Surface_getSurface(env, jSurface);
+        if (surface != NULL) {
+            gbp = surface->getIGraphicBufferProducer();
+        }
     }
 
-    if (camera->setPreviewDisplay(surface) != NO_ERROR) {
-        jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
+    if (camera->setPreviewTexture(gbp) != NO_ERROR) {
+        jniThrowException(env, "java/io/IOException", "setPreviewTexture failed");
     }
 }
 
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index e8a6569..3083cb1 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -176,7 +176,7 @@
     }
 
     sp<Receiver> receiver = new Receiver(queue, messageQueue, eventQ, scratch);
-    receiver->incStrong(clazz);
+    receiver->incStrong((void*)nativeInitSensorEventQueue);
     return jint(receiver.get());
 }
 
@@ -193,7 +193,7 @@
 static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jint eventQ, jint handle) {
     sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
     receiver->destroy();
-    receiver->decStrong(clazz);
+    receiver->decStrong((void*)nativeInitSensorEventQueue);
 }
 
 
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index 923781e..cea5bbf 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -142,7 +142,7 @@
 static jint
 android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz,
         jint requestType, jint request, jint value, jint index,
-        jbyteArray buffer, jint length, jint timeout)
+        jbyteArray buffer, jint start, jint length, jint timeout)
 {
     struct usb_device* device = get_device_from_object(env, thiz);
     if (!device) {
@@ -152,25 +152,22 @@
 
     jbyte* bufferBytes = NULL;
     if (buffer) {
-        if (env->GetArrayLength(buffer) < length) {
-            jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
-            return -1;
-        }
-        bufferBytes = env->GetByteArrayElements(buffer, 0);
+        bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
     }
 
     jint result = usb_device_control_transfer(device, requestType, request,
-            value, index, bufferBytes, length, timeout);
+            value, index, bufferBytes + start, length, timeout);
 
-    if (bufferBytes)
-        env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+    if (bufferBytes) {
+        env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
+    }
 
     return result;
 }
 
 static jint
 android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
-        jint endpoint, jbyteArray buffer, jint length, jint timeout)
+        jint endpoint, jbyteArray buffer, jint start, jint length, jint timeout)
 {
     struct usb_device* device = get_device_from_object(env, thiz);
     if (!device) {
@@ -180,17 +177,14 @@
 
     jbyte* bufferBytes = NULL;
     if (buffer) {
-        if (env->GetArrayLength(buffer) < length) {
-            jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
-            return -1;
-        }
-        bufferBytes = env->GetByteArrayElements(buffer, 0);
+        bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
     }
 
-    jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
+    jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
 
-    if (bufferBytes)
-        env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
+    if (bufferBytes) {
+        env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
+    }
 
     return result;
 }
@@ -235,9 +229,9 @@
     {"native_get_desc",         "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},
     {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
     {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
-    {"native_control_request",  "(IIII[BII)I",
+    {"native_control_request",  "(IIII[BIII)I",
                                         (void *)android_hardware_UsbDeviceConnection_control_request},
-    {"native_bulk_request",     "(I[BII)I",
+    {"native_bulk_request",     "(I[BIII)I",
                                         (void *)android_hardware_UsbDeviceConnection_bulk_request},
     {"native_request_wait",             "()Landroid/hardware/usb/UsbRequest;",
                                         (void *)android_hardware_UsbDeviceConnection_request_wait},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index da2f874..197d240 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -154,10 +154,10 @@
     sp<AudioRecord> old =
             (AudioRecord*)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
     if (ar.get()) {
-        ar->incStrong(thiz);
+        ar->incStrong((void*)setAudioRecord);
     }
     if (old != 0) {
-        old->decStrong(thiz);
+        old->decStrong((void*)setAudioRecord);
     }
     env->SetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (int)ar.get());
     return old;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 9a3736c..e2d34c9 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -191,10 +191,10 @@
     sp<AudioTrack> old =
             (AudioTrack*)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
     if (at.get()) {
-        at->incStrong(thiz);
+        at->incStrong((void*)setAudioTrack);
     }
     if (old != 0) {
-        old->decStrong(thiz);
+        old->decStrong((void*)setAudioTrack);
     }
     env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)at.get());
     return old;
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index f5f22b2..faae11e 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -136,6 +136,10 @@
         result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
                 dns, server, &lease, vendorInfo, domains);
     }
+    if (result != 0) {
+        ALOGD("dhcp_do_request failed");
+    }
+
     env->ReleaseStringUTFChars(ifname, nameStr);
     if (result == 0) {
         env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index b12fdfc..0a97f39 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -23,428 +23,407 @@
 #include "selinux/selinux.h"
 #include "selinux/android.h"
 #include <errno.h>
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+#include <UniquePtr.h>
 
 namespace android {
 
-  static jboolean isSELinuxDisabled = true;
+struct SecurityContext_Delete {
+    void operator()(security_context_t p) const {
+        freecon(p);
+    }
+};
+typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
 
-  static void throw_NullPointerException(JNIEnv *env, const char* msg) {
-    jclass clazz;
-    clazz = env->FindClass("java/lang/NullPointerException");
-    env->ThrowNew(clazz, msg);
-  }
+static jboolean isSELinuxDisabled = true;
 
-  /*
-   * Function: isSELinuxEnabled
-   * Purpose:  checks whether SELinux is enabled/disbaled
-   * Parameters: none
-   * Return value : true (enabled) or false (disabled)
-   * Exceptions: none
-   */
-  static jboolean isSELinuxEnabled(JNIEnv *env, jobject classz) {
-
+/*
+ * Function: isSELinuxEnabled
+ * Purpose:  checks whether SELinux is enabled/disbaled
+ * Parameters: none
+ * Return value : true (enabled) or false (disabled)
+ * Exceptions: none
+ */
+static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
     return !isSELinuxDisabled;
-  }
+}
 
-  /*
-   * Function: isSELinuxEnforced
-   * Purpose: return the current SELinux enforce mode
-   * Parameters: none
-   * Return value: true (enforcing) or false (permissive)
-   * Exceptions: none
-   */
-  static jboolean isSELinuxEnforced(JNIEnv *env, jobject clazz) {
+/*
+ * Function: isSELinuxEnforced
+ * Purpose: return the current SELinux enforce mode
+ * Parameters: none
+ * Return value: true (enforcing) or false (permissive)
+ * Exceptions: none
+ */
+static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
     return (security_getenforce() == 1) ? true : false;
-  }
+}
 
-  /*
-   * Function: setSELinuxEnforce
-   * Purpose: set the SE Linux enforcing mode
-   * Parameters: true (enforcing) or false (permissive)
-   * Return value: true (success) or false (fail)
-   * Exceptions: none
-   */
-  static jboolean setSELinuxEnforce(JNIEnv *env, jobject clazz, jboolean value) {
-    if (isSELinuxDisabled)
-      return false;
+/*
+ * Function: setSELinuxEnforce
+ * Purpose: set the SE Linux enforcing mode
+ * Parameters: true (enforcing) or false (permissive)
+ * Return value: true (success) or false (fail)
+ * Exceptions: none
+ */
+static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-    int enforce = (value) ? 1 : 0;
+    int enforce = value ? 1 : 0;
 
     return (security_setenforce(enforce) != -1) ? true : false;
-  }
+}
 
-  /*
-   * Function: getPeerCon
-   * Purpose: retrieves security context of peer socket
-   * Parameters:
-   *        fileDescriptor: peer socket file as a FileDescriptor object
-   * Returns: jstring representing the security_context of socket or NULL if error
-   * Exceptions: NullPointerException if fileDescriptor object is NULL
-   */
-  static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
-    if (isSELinuxDisabled)
-      return NULL;
+/*
+ * Function: getPeerCon
+ * Purpose: retrieves security context of peer socket
+ * Parameters:
+ *        fileDescriptor: peer socket file as a FileDescriptor object
+ * Returns: jstring representing the security_context of socket or NULL if error
+ * Exceptions: NullPointerException if fileDescriptor object is NULL
+ */
+static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
     if (fileDescriptor == NULL) {
-      throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
-      return NULL;
+        jniThrowNullPointerException(env,
+                "Trying to check security context of a null peer socket.");
+        return NULL;
     }
 
-    security_context_t context = NULL;
-    jstring securityString = NULL;
-
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
     if (env->ExceptionOccurred() != NULL) {
-      ALOGE("There was an issue with retrieving the file descriptor");
-      goto bail;
+        ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
+        return NULL;
     }
 
-    if (getpeercon(fd, &context) == -1)
-      goto bail;
+    security_context_t tmp;
+    int ret = getpeercon(fd, &tmp);
+    Unique_SecurityContext context(tmp);
 
-    ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);
-
-    securityString = env->NewStringUTF(context);
-
-  bail:
-    if (context != NULL)
-      freecon(context);
-
-    return securityString;
-  }
-
-  /*
-   * Function: setFSCreateCon
-   * Purpose: set security context used for creating a new file system object
-   * Parameters:
-   *       context: security_context_t representing the new context of a file system object,
-   *                set to NULL to return to the default policy behavior
-   * Returns: true on success, false on error
-   * Exception: none
-   */
-  static jboolean setFSCreateCon(JNIEnv *env, jobject clazz, jstring context) {
-    if (isSELinuxDisabled)
-      return false;
-
-    char * securityContext = NULL;
-    const char *constant_securityContext = NULL;
-
-    if (context != NULL) {
-      constant_securityContext = env->GetStringUTFChars(context, NULL);
-
-      // GetStringUTFChars returns const char * yet setfscreatecon needs char *
-      securityContext = const_cast<char *>(constant_securityContext);
+    ScopedLocalRef<jstring> contextStr(env, NULL);
+    if (ret != -1) {
+        contextStr.reset(env->NewStringUTF(context.get()));
     }
 
-    int ret;
-    if ((ret = setfscreatecon(securityContext)) == -1)
-      goto bail;
+    ALOGV("getPeerCon(%d) => %s", fd, contextStr.get());
+    return contextStr.release();
+}
 
-    ALOGV("setFSCreateCon: set new security context to '%s' ", context == NULL ? "default", context);
+/*
+ * Function: setFSCreateCon
+ * Purpose: set security context used for creating a new file system object
+ * Parameters:
+ *       context: security_context_t representing the new context of a file system object,
+ *                set to NULL to return to the default policy behavior
+ * Returns: true on success, false on error
+ * Exception: none
+ */
+static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-  bail:
-    if (constant_securityContext != NULL)
-      env->ReleaseStringUTFChars(context, constant_securityContext);
+    UniquePtr<ScopedUtfChars> context;
+    const char* context_c_str = NULL;
+    if (contextStr != NULL) {
+        context.reset(new ScopedUtfChars(env, contextStr));
+        context_c_str = context->c_str();
+        if (context_c_str == NULL) {
+            return false;
+        }
+    }
+
+    int ret = setfscreatecon(const_cast<char *>(context_c_str));
+
+    ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
 
     return (ret == 0) ? true : false;
-  }
+}
 
-  /*
-   * Function: setFileCon
-   * Purpose:  set the security context of a file object
-   * Parameters:
-   *       path: the location of the file system object
-   *       con: the new security context of the file system object
-   * Returns: true on success, false on error
-   * Exception: NullPointerException is thrown if either path or context strign are NULL
-   */
-  static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) {
-    if (isSELinuxDisabled)
-      return false;
-
-    if (path == NULL) {
-      throw_NullPointerException(env, "Trying to change the security context of a NULL file object.");
-      return false;
+/*
+ * Function: setFileCon
+ * Purpose:  set the security context of a file object
+ * Parameters:
+ *       path: the location of the file system object
+ *       context: the new security context of the file system object
+ * Returns: true on success, false on error
+ * Exception: NullPointerException is thrown if either path or context strign are NULL
+ */
+static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
+    if (isSELinuxDisabled) {
+        return false;
     }
 
-    if (con == NULL) {
-      throw_NullPointerException(env, "Trying to set the security context of a file object with NULL.");
-      return false;
+    ScopedUtfChars path(env, pathStr);
+    if (path.c_str() == NULL) {
+        return false;
     }
 
-    const char *objectPath = env->GetStringUTFChars(path, NULL);
-    const char *constant_con = env->GetStringUTFChars(con, NULL);
+    ScopedUtfChars context(env, contextStr);
+    if (context.c_str() == NULL) {
+        return false;
+    }
 
     // GetStringUTFChars returns const char * yet setfilecon needs char *
-    char *newCon = const_cast<char *>(constant_con);
+    char *tmp = const_cast<char *>(context.c_str());
+    int ret = setfilecon(path.c_str(), tmp);
 
-    int ret;
-    if ((ret = setfilecon(objectPath, newCon)) == -1)
-      goto bail;
-
-    ALOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath);
-
-  bail:
-    env->ReleaseStringUTFChars(path, objectPath);
-    env->ReleaseStringUTFChars(con, constant_con);
+    ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
     return (ret == 0) ? true : false;
-  }
+}
 
-  /*
-   * Function: getFileCon
-   * Purpose: retrieves the context associated with the given path in the file system
-   * Parameters:
-   *        path: given path in the file system
-   * Returns:
-   *        string representing the security context string of the file object
-   *        the string may be NULL if an error occured
-   * Exceptions: NullPointerException if the path object is null
-   */
-  static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) {
-    if (isSELinuxDisabled)
-      return NULL;
-
-    if (path == NULL) {
-      throw_NullPointerException(env, "Trying to check security context of a null path.");
-      return NULL;
+/*
+ * Function: getFileCon
+ * Purpose: retrieves the context associated with the given path in the file system
+ * Parameters:
+ *        path: given path in the file system
+ * Returns:
+ *        string representing the security context string of the file object
+ *        the string may be NULL if an error occured
+ * Exceptions: NullPointerException if the path object is null
+ */
+static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
+    if (isSELinuxDisabled) {
+        return NULL;
     }
 
-    const char *objectPath = env->GetStringUTFChars(path, NULL);
+    ScopedUtfChars path(env, pathStr);
+    if (path.c_str() == NULL) {
+        return NULL;
+    }
 
-    security_context_t context = NULL;
-    jstring securityString = NULL;
+    security_context_t tmp;
+    int ret = getfilecon(path.c_str(), &tmp);
+    Unique_SecurityContext context(tmp);
 
-    if (getfilecon(objectPath, &context) == -1)
-      goto bail;
+    ScopedLocalRef<jstring> securityString(env, NULL);
+    if (ret != -1) {
+        securityString.reset(env->NewStringUTF(context.get()));
+    }
 
-    ALOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath);
+    ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
+    return securityString.release();
+}
 
-    securityString = env->NewStringUTF(context);
+/*
+ * Function: getCon
+ * Purpose: Get the context of the current process.
+ * Parameters: none
+ * Returns: a jstring representing the security context of the process,
+ *          the jstring may be NULL if there was an error
+ * Exceptions: none
+ */
+static jstring getCon(JNIEnv *env, jobject) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
-  bail:
-    if (context != NULL)
-      freecon(context);
+    security_context_t tmp;
+    int ret = getcon(&tmp);
+    Unique_SecurityContext context(tmp);
 
-    env->ReleaseStringUTFChars(path, objectPath);
+    ScopedLocalRef<jstring> securityString(env, NULL);
+    if (ret != -1) {
+        securityString.reset(env->NewStringUTF(context.get()));
+    }
 
-    return securityString;
-  }
+    ALOGV("getCon() => %s", context.get());
+    return securityString.release();
+}
 
-  /*
-   * Function: getCon
-   * Purpose: Get the context of the current process.
-   * Parameters: none
-   * Returns: a jstring representing the security context of the process,
-   *          the jstring may be NULL if there was an error
-   * Exceptions: none
-   */
-  static jstring getCon(JNIEnv *env, jobject clazz) {
-    if (isSELinuxDisabled)
-      return NULL;
+/*
+ * Function: getPidCon
+ * Purpose: Get the context of a process identified by its pid
+ * Parameters:
+ *            pid: a jint representing the process
+ * Returns: a jstring representing the security context of the pid,
+ *          the jstring may be NULL if there was an error
+ * Exceptions: none
+ */
+static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
-    security_context_t context = NULL;
-    jstring securityString = NULL;
+    security_context_t tmp;
+    int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
+    Unique_SecurityContext context(tmp);
 
-    if (getcon(&context) == -1)
-      goto bail;
+    ScopedLocalRef<jstring> securityString(env, NULL);
+    if (ret != -1) {
+        securityString.reset(env->NewStringUTF(context.get()));
+    }
 
-    ALOGV("getCon: Successfully retrieved context '%s'", context);
+    ALOGV("getPidCon(%d) => %s", pid, context.get());
+    return securityString.release();
+}
 
-    securityString = env->NewStringUTF(context);
-
-  bail:
-    if (context != NULL)
-      freecon(context);
-
-    return securityString;
-  }
-
-  /*
-   * Function: getPidCon
-   * Purpose: Get the context of a process identified by its pid
-   * Parameters:
-   *            pid: a jint representing the process
-   * Returns: a jstring representing the security context of the pid,
-   *          the jstring may be NULL if there was an error
-   * Exceptions: none
-   */
-  static jstring getPidCon(JNIEnv *env, jobject clazz, jint pid) {
-    if (isSELinuxDisabled)
-      return NULL;
-
-    security_context_t context = NULL;
-    jstring securityString = NULL;
-
-    pid_t checkPid = (pid_t)pid;
-
-    if (getpidcon(checkPid, &context) == -1)
-      goto bail;
-
-    ALOGV("getPidCon: Successfully retrived context '%s' for pid '%d'", context, checkPid);
-
-    securityString = env->NewStringUTF(context);
-
-  bail:
-    if (context != NULL)
-      freecon(context);
-
-    return securityString;
-  }
-
-  /*
-   * Function: getBooleanNames
-   * Purpose: Gets a list of the SELinux boolean names.
-   * Parameters: None
-   * Returns: an array of strings  containing the SELinux boolean names.
-   *          returns NULL string on error
-   * Exceptions: None
-   */
-  static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv clazz) {
-    if (isSELinuxDisabled)
-      return NULL;
+/*
+ * Function: getBooleanNames
+ * Purpose: Gets a list of the SELinux boolean names.
+ * Parameters: None
+ * Returns: an array of strings  containing the SELinux boolean names.
+ *          returns NULL string on error
+ * Exceptions: None
+ */
+static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
     char **list;
-    int i, len, ret;
-    jclass stringClass;
-    jobjectArray stringArray = NULL;
+    int len;
+    if (security_get_boolean_names(&list, &len) == -1) {
+        return NULL;
+    }
 
-    if (security_get_boolean_names(&list, &len) == -1)
-      return NULL;
-
-    stringClass = env->FindClass("java/lang/String");
-    stringArray = env->NewObjectArray(len, stringClass, env->NewStringUTF(""));
-    for (i = 0; i < len; i++) {
-      jstring obj;
-      obj = env->NewStringUTF(list[i]);
-      env->SetObjectArrayElement(stringArray, i, obj);
-      env->DeleteLocalRef(obj);
-      free(list[i]);
+    jclass stringClass = env->FindClass("java/lang/String");
+    jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL);
+    for (int i = 0; i < len; i++) {
+        ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i]));
+        env->SetObjectArrayElement(stringArray, i, obj.get());
+        free(list[i]);
     }
     free(list);
 
     return stringArray;
-  }
+}
 
-  /*
-   * Function: getBooleanValue
-   * Purpose: Gets the value for the given SELinux boolean name.
-   * Parameters:
-   *            String: The name of the SELinux boolean.
-   * Returns: a boolean: (true) boolean is set or (false) it is not.
-   * Exceptions: None
-   */
-  static jboolean getBooleanValue(JNIEnv *env, jobject clazz, jstring name) {
-    if (isSELinuxDisabled)
-      return false;
+/*
+ * Function: getBooleanValue
+ * Purpose: Gets the value for the given SELinux boolean name.
+ * Parameters:
+ *            String: The name of the SELinux boolean.
+ * Returns: a boolean: (true) boolean is set or (false) it is not.
+ * Exceptions: None
+ */
+static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-    const char *boolean_name;
-    int ret;
+    if (nameStr == NULL) {
+        return false;
+    }
 
-    if (name == NULL)
-      return false;
-    boolean_name = env->GetStringUTFChars(name, NULL);
-    ret = security_get_boolean_active(boolean_name);
-    env->ReleaseStringUTFChars(name, boolean_name);
+    ScopedUtfChars name(env, nameStr);
+    int ret = security_get_boolean_active(name.c_str());
+
+    ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
     return (ret == 1) ? true : false;
-  }
+}
 
-  /*
-   * Function: setBooleanNames
-   * Purpose: Sets the value for the given SELinux boolean name.
-   * Parameters:
-   *            String: The name of the SELinux boolean.
-   *            Boolean: The new value of the SELinux boolean.
-   * Returns: a boolean indicating whether or not the operation succeeded.
-   * Exceptions: None
-   */
-  static jboolean setBooleanValue(JNIEnv *env, jobject clazz, jstring name, jboolean value) {
-    if (isSELinuxDisabled)
-      return false;
+/*
+ * Function: setBooleanNames
+ * Purpose: Sets the value for the given SELinux boolean name.
+ * Parameters:
+ *            String: The name of the SELinux boolean.
+ *            Boolean: The new value of the SELinux boolean.
+ * Returns: a boolean indicating whether or not the operation succeeded.
+ * Exceptions: None
+ */
+static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-    const char *boolean_name = NULL;
-    int ret;
+    if (nameStr == NULL) {
+        return false;
+    }
 
-    if (name == NULL)
-      return false;
-    boolean_name = env->GetStringUTFChars(name, NULL);
-    ret = security_set_boolean(boolean_name, (value) ? 1 : 0);
-    env->ReleaseStringUTFChars(name, boolean_name);
-    if (ret)
-      return false;
+    ScopedUtfChars name(env, nameStr);
+    int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
+    if (ret) {
+        return false;
+    }
 
-    if (security_commit_booleans() == -1)
-      return false;
+    if (security_commit_booleans() == -1) {
+        return false;
+    }
 
     return true;
-  }
+}
 
-  /*
-   * Function: checkSELinuxAccess
-   * Purpose: Check permissions between two security contexts.
-   * Parameters: scon: subject security context as a string
-   *             tcon: object security context as a string
-   *             tclass: object's security class name as a string
-   *             perm: permission name as a string
-   * Returns: boolean: (true) if permission was granted, (false) otherwise
-   * Exceptions: None
-   */
-  static jboolean checkSELinuxAccess(JNIEnv *env, jobject clazz, jstring scon, jstring tcon, jstring tclass, jstring perm) {
-    if (isSELinuxDisabled)
-      return true;
+/*
+ * Function: checkSELinuxAccess
+ * Purpose: Check permissions between two security contexts.
+ * Parameters: subjectContextStr: subject security context as a string
+ *             objectContextStr: object security context as a string
+ *             objectClassStr: object's security class name as a string
+ *             permissionStr: permission name as a string
+ * Returns: boolean: (true) if permission was granted, (false) otherwise
+ * Exceptions: None
+ */
+static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
+        jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
+    if (isSELinuxDisabled) {
+        return true;
+    }
 
-    int accessGranted = -1;
+    ScopedUtfChars subjectContext(env, subjectContextStr);
+    if (subjectContext.c_str() == NULL) {
+        return false;
+    }
 
-    const char *const_scon, *const_tcon, *mytclass, *myperm;
-    char *myscon, *mytcon;
+    ScopedUtfChars objectContext(env, objectContextStr);
+    if (objectContext.c_str() == NULL) {
+        return false;
+    }
 
-    if (scon == NULL || tcon == NULL || tclass == NULL || perm == NULL)
-      goto bail;
+    ScopedUtfChars objectClass(env, objectClassStr);
+    if (objectClass.c_str() == NULL) {
+        return false;
+    }
 
-    const_scon = env->GetStringUTFChars(scon, NULL);
-    const_tcon = env->GetStringUTFChars(tcon, NULL);
-    mytclass   = env->GetStringUTFChars(tclass, NULL);
-    myperm     = env->GetStringUTFChars(perm, NULL);
+    ScopedUtfChars permission(env, permissionStr);
+    if (permission.c_str() == NULL) {
+        return false;
+    }
 
-    // selinux_check_access needs char* for some
-    myscon = const_cast<char *>(const_scon);
-    mytcon = const_cast<char *>(const_tcon);
+    char *tmp1 = const_cast<char *>(subjectContext.c_str());
+    char *tmp2 = const_cast<char *>(objectContext.c_str());
+    int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
+            NULL);
 
-    accessGranted = selinux_check_access(myscon, mytcon, mytclass, myperm, NULL);
+    ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
+            objectClass.c_str(), permission.c_str(), accessGranted);
 
-    ALOGV("selinux_check_access returned %d", accessGranted);
-
-    env->ReleaseStringUTFChars(scon, const_scon);
-    env->ReleaseStringUTFChars(tcon, const_tcon);
-    env->ReleaseStringUTFChars(tclass, mytclass);
-    env->ReleaseStringUTFChars(perm, myperm);
-
-  bail:
     return (accessGranted == 0) ? true : false;
-  }
+}
 
-  /*
-   * Function: native_restorecon
-   * Purpose: restore default SELinux security context
-   * Parameters: pathname: the pathname for the file to be relabeled
-   * Returns: boolean: (true) file label successfully restored, (false) otherwise
-   * Exceptions: none
-   */
-  static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
-    if (isSELinuxDisabled)
-      return true;
+/*
+ * Function: native_restorecon
+ * Purpose: restore default SELinux security context
+ * Parameters: pathname: the pathname for the file to be relabeled
+ * Returns: boolean: (true) file label successfully restored, (false) otherwise
+ * Exceptions: none
+ */
+static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
+    if (isSELinuxDisabled) {
+        return true;
+    }
 
-    const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL));
-    int ret = selinux_android_restorecon(file);
-    env->ReleaseStringUTFChars(pathname, file);
+    ScopedUtfChars pathname(env, pathnameStr);
+    if (pathname.c_str() == NULL) {
+        ALOGV("restorecon(%p) => threw exception", pathname);
+        return false;
+    }
+
+    int ret = selinux_android_restorecon(pathname.c_str());
+    ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
     return (ret == 0);
-  }
+}
 
-  /*
-   * JNI registration.
-   */
-  static JNINativeMethod method_table[] = {
-
+/*
+ * JNI registration.
+ */
+static JNINativeMethod method_table[] = {
     /* name,                     signature,                    funcPtr */
     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
     { "getBooleanNames"          , "()[Ljava/lang/String;"                        , (void*)getBooleanNames  },
@@ -460,25 +439,25 @@
     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
     { "setSELinuxEnforce"        , "(Z)Z"                                         , (void*)setSELinuxEnforce},
-  };
+};
 
-  static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
     LOG_PRI_VA(ANDROID_LOG_ERROR, "SELinux", fmt, ap);
     va_end(ap);
     return 0;
-  }
+}
 
-  int register_android_os_SELinux(JNIEnv *env) {
+int register_android_os_SELinux(JNIEnv *env) {
     union selinux_callback cb;
     cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
     isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
 
-    return AndroidRuntime::registerNativeMethods(
-         env, "android/os/SELinux",
-         method_table, NELEM(method_table));
-  }
+    return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
+            NELEM(method_table));
+}
+
 }
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index f028c86d..00ecd0a 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -18,6 +18,9 @@
 
 #include <JNIHelp.h>
 #include <ScopedUtfChars.h>
+#include <ScopedStringChars.h>
+
+#include <utils/String8.h>
 
 #include <cutils/trace.h>
 #include <cutils/log.h>
@@ -36,8 +39,20 @@
 
 static void android_os_Trace_nativeTraceBegin(JNIEnv* env, jclass clazz,
         jlong tag, jstring nameStr) {
-    ScopedUtfChars name(env, nameStr);
-    atrace_begin(tag, name.c_str());
+    const size_t MAX_SECTION_NAME_LEN = 127;
+    ScopedStringChars jchars(env, nameStr);
+    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()),
+            jchars.size());
+    size_t size = utf8Chars.size();
+    char* str = utf8Chars.lockBuffer(size);
+    for (size_t i = 0; i < size; i++) {
+        char c = str[i];
+        if (c == '\0' || c == '\n' || c == '|') {
+            str[i] = ' ';
+        }
+    }
+    utf8Chars.unlockBuffer();
+    atrace_begin(tag, utf8Chars.string());
 }
 
 static void android_os_Trace_nativeTraceEnd(JNIEnv* env, jclass clazz,
@@ -45,6 +60,11 @@
     atrace_end(tag);
 }
 
+static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv* env,
+        jclass clazz, jboolean allowed) {
+    atrace_set_debuggable(allowed);
+}
+
 static JNINativeMethod gTraceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeGetEnabledTags",
@@ -59,6 +79,9 @@
     { "nativeTraceEnd",
             "(J)V",
             (void*)android_os_Trace_nativeTraceEnd },
+    { "nativeSetAppTracingAllowed",
+            "(Z)V",
+            (void*)android_os_Trace_nativeSetAppTracingAllowed },
 };
 
 int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 881d9a0..8766cf9 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -93,14 +93,6 @@
 
 // ----------------------------------------------------------------------------
 
-static struct weakreference_offsets_t
-{
-    // Class state.
-    jclass mClass;
-    jmethodID mGet;
-
-} gWeakReferenceOffsets;
-
 static struct error_offsets_t
 {
     jclass mClass;
@@ -570,7 +562,7 @@
     // Someone else's...  do we know about it?
     jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
     if (object != NULL) {
-        jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet);
+        jobject res = jniGetReferent(env, object);
         if (res != NULL) {
             ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
             return res;
@@ -586,7 +578,7 @@
         LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object);
         // The proxy holds a reference to the native object.
         env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
-        val->incStrong(object);
+        val->incStrong((void*)javaObjectForIBinder);
 
         // The native object needs to hold a weak reference back to the
         // proxy, so we can retrieve the same proxy if it is still active.
@@ -1187,7 +1179,7 @@
     env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
     env->SetIntField(obj, gBinderProxyOffsets.mOrgue, 0);
     drl->decStrong((void*)javaObjectForIBinder);
-    b->decStrong(obj);
+    b->decStrong((void*)javaObjectForIBinder);
 
     IPCThreadState::self()->flushCommands();
 }
@@ -1211,13 +1203,6 @@
 {
     jclass clazz;
 
-    clazz = env->FindClass("java/lang/ref/WeakReference");
-    LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.ref.WeakReference");
-    gWeakReferenceOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    gWeakReferenceOffsets.mGet
-        = env->GetMethodID(clazz, "get", "()Ljava/lang/Object;");
-    assert(gWeakReferenceOffsets.mGet);
-
     clazz = env->FindClass("java/lang/Error");
     LOG_FATAL_IF(clazz == NULL, "Unable to find class java.lang.Error");
     gErrorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index ba62f6d..b87fe27 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -568,9 +568,9 @@
 // ----------------------------------------------------------------------------
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, flags);
     if (value == NULL) {
         return;
     }
@@ -584,9 +584,9 @@
 }
 
 static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, flags);
     if (value == NULL) {
         return;
     }
@@ -599,9 +599,9 @@
 
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
-        SkPaint* paint) {
+        int flags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, start, count, contextCount);
+            text, start, count, contextCount, flags);
     if (value == NULL) {
         return;
     }
@@ -616,62 +616,64 @@
 
 static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, jint flags, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
-    renderText(renderer, textArray + index, count, x, y, paint);
+    renderText(renderer, textArray + index, count, x, y, flags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        jfloat x, jfloat y, SkPaint* paint) {
+        jfloat x, jfloat y, jint flags, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
-    renderText(renderer, textArray + start, end - start, x, y, paint);
+    renderText(renderer, textArray + start, end - start, x, y, flags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     renderTextOnPath(renderer, textArray + index, count, path,
-            hOffset, vOffset, paint);
+            hOffset, vOffset, flags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
 }
 
 static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        SkPath* path, jfloat hOffset, jfloat vOffset, SkPaint* paint) {
+        SkPath* path, jfloat hOffset, jfloat vOffset, jint flags, SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
     renderTextOnPath(renderer, textArray + start, end - start, path,
-            hOffset, vOffset, paint);
+            hOffset, vOffset, flags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jcharArray text, jint index, jint count,
-        jint contextIndex, jint contextCount, jfloat x, jfloat y, SkPaint* paint) {
+        jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
+        SkPaint* paint) {
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
-            count, contextCount, x, y, paint);
+            count, contextCount, x, y, dirFlags, paint);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
  }
 
 static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jstring text, jint start, jint end,
-        jint contextStart, int contextEnd, jfloat x, jfloat y, SkPaint* paint) {
+        jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
+        SkPaint* paint) {
     const jchar* textArray = env->GetStringChars(text, NULL);
     jint count = end - start;
     jint contextCount = contextEnd - contextStart;
     renderTextRun(renderer, textArray + contextStart, start - contextStart,
-            count, contextCount, x, y, paint);
+            count, contextCount, x, y, dirFlags, paint);
     env->ReleaseStringChars(text, textArray);
 }
 
 static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
-        const jfloat* positions, SkPaint* paint) {
+        const jfloat* positions, jint dirFlags, SkPaint* paint) {
     sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
-            text, 0, count, count);
+            text, 0, count, count, dirFlags);
     if (value == NULL) {
         return;
     }
@@ -689,7 +691,7 @@
     jchar* textArray = env->GetCharArrayElements(text, NULL);
     jfloat* positions = env->GetFloatArrayElements(pos, NULL);
 
-    renderPosText(renderer, textArray + index, count, positions, paint);
+    renderPosText(renderer, textArray + index, count, positions, kBidi_LTR, paint);
 
     env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
     env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -701,7 +703,7 @@
     const jchar* textArray = env->GetStringChars(text, NULL);
     jfloat* positions = env->GetFloatArrayElements(pos, NULL);
 
-    renderPosText(renderer, textArray + start, end - start, positions, paint);
+    renderPosText(renderer, textArray + start, end - start, positions, kBidi_LTR, paint);
 
     env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT);
     env->ReleaseStringChars(text, textArray);
@@ -866,8 +868,8 @@
 }
 
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
-        OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
-    renderer->drawLayer(layer, x, y, paint);
+        OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y) {
+    renderer->drawLayer(layer, x, y);
 }
 
 static jboolean android_view_GLES20Canvas_copyLayer(JNIEnv* env, jobject clazz,
@@ -1005,16 +1007,16 @@
     { "nSetupPaintFilter",  "(III)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
     { "nResetPaintFilter",  "(I)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
 
-    { "nDrawText",          "(I[CIIFFI)V",    (void*) android_view_GLES20Canvas_drawTextArray },
-    { "nDrawText",          "(ILjava/lang/String;IIFFI)V",
+    { "nDrawText",          "(I[CIIFFII)V",    (void*) android_view_GLES20Canvas_drawTextArray },
+    { "nDrawText",          "(ILjava/lang/String;IIFFII)V",
             (void*) android_view_GLES20Canvas_drawText },
 
-    { "nDrawTextOnPath",    "(I[CIIIFFI)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
-    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFI)V",
+    { "nDrawTextOnPath",    "(I[CIIIFFII)V",   (void*) android_view_GLES20Canvas_drawTextArrayOnPath },
+    { "nDrawTextOnPath",    "(ILjava/lang/String;IIIFFII)V",
             (void*) android_view_GLES20Canvas_drawTextOnPath },
 
-    { "nDrawTextRun",       "(I[CIIIIFFI)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
-    { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFI)V",
+    { "nDrawTextRun",       "(I[CIIIIFFII)V",  (void*) android_view_GLES20Canvas_drawTextRunArray },
+    { "nDrawTextRun",       "(ILjava/lang/String;IIIIFFII)V",
             (void*) android_view_GLES20Canvas_drawTextRun },
 
     { "nDrawPosText",       "(I[CII[FI)V",     (void*) android_view_GLES20Canvas_drawPosTextArray },
@@ -1048,7 +1050,7 @@
     { "nClearLayerTexture",      "(I)V",       (void*) android_view_GLES20Canvas_clearLayerTexture },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
-    { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
+    { "nDrawLayer",              "(IIFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(II)Z",      (void*) android_view_GLES20Canvas_copyLayer },
     { "nClearLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
     { "nPushLayerUpdate",        "(II)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 9c44a59..9fa9fe4 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -246,6 +246,15 @@
     return name;
 }
 
+static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobject otherObj) {
+    NativeInputChannel* nativeInputChannel =
+            android_view_InputChannel_getNativeInputChannel(env, obj);
+    if (nativeInputChannel) {
+        android_view_InputChannel_setNativeInputChannel(env, otherObj,
+                new NativeInputChannel(nativeInputChannel->getInputChannel()->dup()));
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gInputChannelMethods[] = {
@@ -262,6 +271,8 @@
             (void*)android_view_InputChannel_nativeWriteToParcel },
     { "nativeGetName", "()Ljava/lang/String;",
             (void*)android_view_InputChannel_nativeGetName },
+    { "nativeDup", "(Landroid/view/InputChannel;)V",
+            (void*)android_view_InputChannel_nativeDup },
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 576f831..e3a54a8 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -62,8 +62,8 @@
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
         const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
-        env->CallVoidMethod(inputDeviceObj.get(), gInputDeviceClassInfo.addMotionRange,
-                range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
+        env->CallVoidMethod(inputDeviceObj.get(), gInputDeviceClassInfo.addMotionRange, range.axis,
+                range.source, range.min, range.max, range.flat, range.fuzz, range.resolution);
         if (env->ExceptionCheck()) {
             return NULL;
         }
@@ -90,7 +90,7 @@
             "<init>", "(IILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;Z)V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
-            "addMotionRange", "(IIFFFF)V");
+            "addMotionRange", "(IIFFFFF)V");
 
     return 0;
 }
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 9501cf2..c350521 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -34,6 +34,8 @@
 #include "android_view_KeyEvent.h"
 #include "android_view_MotionEvent.h"
 
+#include <ScopedLocalRef.h>
+
 namespace android {
 
 static struct {
@@ -47,7 +49,7 @@
 class NativeInputEventReceiver : public LooperCallback {
 public:
     NativeInputEventReceiver(JNIEnv* env,
-            jobject receiverObj, const sp<InputChannel>& inputChannel,
+            jobject receiverWeak, const sp<InputChannel>& inputChannel,
             const sp<MessageQueue>& messageQueue);
 
     status_t initialize();
@@ -59,7 +61,7 @@
     virtual ~NativeInputEventReceiver();
 
 private:
-    jobject mReceiverObjGlobal;
+    jobject mReceiverWeakGlobal;
     InputConsumer mInputConsumer;
     sp<MessageQueue> mMessageQueue;
     PreallocatedInputEventFactory mInputEventFactory;
@@ -74,9 +76,9 @@
 
 
 NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
-        jobject receiverObj, const sp<InputChannel>& inputChannel,
+        jobject receiverWeak, const sp<InputChannel>& inputChannel,
         const sp<MessageQueue>& messageQueue) :
-        mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
+        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
         mInputConsumer(inputChannel), mMessageQueue(messageQueue),
         mBatchedInputEventPending(false) {
 #if DEBUG_DISPATCH_CYCLE
@@ -86,7 +88,7 @@
 
 NativeInputEventReceiver::~NativeInputEventReceiver() {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->DeleteGlobalRef(mReceiverObjGlobal);
+    env->DeleteGlobalRef(mReceiverWeakGlobal);
 }
 
 status_t NativeInputEventReceiver::initialize() {
@@ -118,8 +120,13 @@
 
 int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
-        ALOGE("channel '%s' ~ Publisher closed input channel or an error occurred.  "
+#if DEBUG_DISPATCH_CYCLE
+        // This error typically occurs when the publisher has closed the input channel
+        // as part of removing a window or finishing an IME session, in which case
+        // the consumer will soon be disposed as well.
+        ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred.  "
                 "events=0x%x", getInputChannelName(), events);
+#endif
         return 0; // remove the callback
     }
 
@@ -146,6 +153,7 @@
         mBatchedInputEventPending = false;
     }
 
+    ScopedLocalRef<jobject> receiverObj(env, NULL);
     bool skipCallbacks = false;
     for (;;) {
         uint32_t seq;
@@ -157,12 +165,21 @@
                 if (!skipCallbacks && !mBatchedInputEventPending
                         && mInputConsumer.hasPendingBatch()) {
                     // There is a pending batch.  Come back later.
+                    if (!receiverObj.get()) {
+                        receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
+                        if (!receiverObj.get()) {
+                            ALOGW("channel '%s' ~ Receiver object was finalized "
+                                    "without being disposed.", getInputChannelName());
+                            return DEAD_OBJECT;
+                        }
+                    }
+
                     mBatchedInputEventPending = true;
 #if DEBUG_DISPATCH_CYCLE
                     ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
                             getInputChannelName());
 #endif
-                    env->CallVoidMethod(mReceiverObjGlobal,
+                    env->CallVoidMethod(receiverObj.get(),
                             gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
                     if (env->ExceptionCheck()) {
                         ALOGE("Exception dispatching batched input events.");
@@ -178,6 +195,15 @@
         assert(inputEvent);
 
         if (!skipCallbacks) {
+            if (!receiverObj.get()) {
+                receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
+                if (!receiverObj.get()) {
+                    ALOGW("channel '%s' ~ Receiver object was finalized "
+                            "without being disposed.", getInputChannelName());
+                    return DEAD_OBJECT;
+                }
+            }
+
             jobject inputEventObj;
             switch (inputEvent->getType()) {
             case AINPUT_EVENT_TYPE_KEY:
@@ -205,12 +231,13 @@
 #if DEBUG_DISPATCH_CYCLE
                 ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
 #endif
-                env->CallVoidMethod(mReceiverObjGlobal,
+                env->CallVoidMethod(receiverObj.get(),
                         gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                 if (env->ExceptionCheck()) {
                     ALOGE("Exception dispatching input event.");
                     skipCallbacks = true;
                 }
+                env->DeleteLocalRef(inputEventObj);
             } else {
                 ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
                 skipCallbacks = true;
@@ -224,7 +251,7 @@
 }
 
 
-static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
+static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
         jobject inputChannelObj, jobject messageQueueObj) {
     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
             inputChannelObj);
@@ -240,7 +267,7 @@
     }
 
     sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
-            receiverObj, inputChannel, messageQueue);
+            receiverWeak, inputChannel, messageQueue);
     status_t status = receiver->initialize();
     if (status) {
         String8 message;
@@ -288,7 +315,7 @@
 static JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
-            "(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
+            "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
             (void*)nativeInit },
     { "nativeDispose", "(I)V",
             (void*)nativeDispose },
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
new file mode 100644
index 0000000..b46eb4b
--- /dev/null
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "InputEventSender"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages about the dispatch cycle.
+#define DEBUG_DISPATCH_CYCLE 0
+
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <androidfw/InputTransport.h>
+#include "android_os_MessageQueue.h"
+#include "android_view_InputChannel.h"
+#include "android_view_KeyEvent.h"
+#include "android_view_MotionEvent.h"
+
+#include <ScopedLocalRef.h>
+
+namespace android {
+
+static struct {
+    jclass clazz;
+
+    jmethodID dispatchInputEventFinished;
+} gInputEventSenderClassInfo;
+
+
+class NativeInputEventSender : public LooperCallback {
+public:
+    NativeInputEventSender(JNIEnv* env,
+            jobject senderWeak, const sp<InputChannel>& inputChannel,
+            const sp<MessageQueue>& messageQueue);
+
+    status_t initialize();
+    void dispose();
+    status_t sendKeyEvent(uint32_t seq, const KeyEvent* event);
+    status_t sendMotionEvent(uint32_t seq, const MotionEvent* event);
+
+protected:
+    virtual ~NativeInputEventSender();
+
+private:
+    jobject mSenderWeakGlobal;
+    InputPublisher mInputPublisher;
+    sp<MessageQueue> mMessageQueue;
+    KeyedVector<uint32_t, uint32_t> mPublishedSeqMap;
+    uint32_t mNextPublishedSeq;
+
+    const char* getInputChannelName() {
+        return mInputPublisher.getChannel()->getName().string();
+    }
+
+    virtual int handleEvent(int receiveFd, int events, void* data);
+    status_t receiveFinishedSignals(JNIEnv* env);
+};
+
+
+NativeInputEventSender::NativeInputEventSender(JNIEnv* env,
+        jobject senderWeak, const sp<InputChannel>& inputChannel,
+        const sp<MessageQueue>& messageQueue) :
+        mSenderWeakGlobal(env->NewGlobalRef(senderWeak)),
+        mInputPublisher(inputChannel), mMessageQueue(messageQueue),
+        mNextPublishedSeq(1) {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Initializing input event sender.", getInputChannelName());
+#endif
+}
+
+NativeInputEventSender::~NativeInputEventSender() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mSenderWeakGlobal);
+}
+
+status_t NativeInputEventSender::initialize() {
+    int receiveFd = mInputPublisher.getChannel()->getFd();
+    mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
+    return OK;
+}
+
+void NativeInputEventSender::dispose() {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Disposing input event sender.", getInputChannelName());
+#endif
+
+    mMessageQueue->getLooper()->removeFd(mInputPublisher.getChannel()->getFd());
+}
+
+status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* event) {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Sending key event, seq=%u.", getInputChannelName(), seq);
+#endif
+
+    uint32_t publishedSeq = mNextPublishedSeq++;
+    status_t status = mInputPublisher.publishKeyEvent(publishedSeq,
+            event->getDeviceId(), event->getSource(), event->getAction(), event->getFlags(),
+            event->getKeyCode(), event->getScanCode(), event->getMetaState(),
+            event->getRepeatCount(), event->getDownTime(), event->getEventTime());
+    if (status) {
+        ALOGW("Failed to send key event on channel '%s'.  status=%d",
+                getInputChannelName(), status);
+        return status;
+    }
+    mPublishedSeqMap.add(publishedSeq, seq);
+    return OK;
+}
+
+status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent* event) {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Sending motion event, seq=%u.", getInputChannelName(), seq);
+#endif
+
+    uint32_t publishedSeq;
+    for (size_t i = 0; i <= event->getHistorySize(); i++) {
+        publishedSeq = mNextPublishedSeq++;
+        status_t status = mInputPublisher.publishMotionEvent(publishedSeq,
+                event->getDeviceId(), event->getSource(), event->getAction(), event->getFlags(),
+                event->getEdgeFlags(), event->getMetaState(), event->getButtonState(),
+                event->getXOffset(), event->getYOffset(),
+                event->getXPrecision(), event->getYPrecision(),
+                event->getDownTime(), event->getHistoricalEventTime(i),
+                event->getPointerCount(), event->getPointerProperties(),
+                event->getHistoricalRawPointerCoords(0, i));
+        if (status) {
+            ALOGW("Failed to send motion event sample on channel '%s'.  status=%d",
+                    getInputChannelName(), status);
+            return status;
+        }
+    }
+    mPublishedSeqMap.add(publishedSeq, seq);
+    return OK;
+}
+
+int NativeInputEventSender::handleEvent(int receiveFd, int events, void* data) {
+    if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+#if DEBUG_DISPATCH_CYCLE
+        // This error typically occurs when the consumer has closed the input channel
+        // as part of finishing an IME session, in which case the publisher will
+        // soon be disposed as well.
+        ALOGD("channel '%s' ~ Consumer closed input channel or an error occurred.  "
+                "events=0x%x", getInputChannelName(), events);
+#endif
+        return 0; // remove the callback
+    }
+
+    if (!(events & ALOOPER_EVENT_INPUT)) {
+        ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
+                "events=0x%x", getInputChannelName(), events);
+        return 1;
+    }
+
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    status_t status = receiveFinishedSignals(env);
+    mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
+    return status == OK || status == NO_MEMORY ? 1 : 0;
+}
+
+status_t NativeInputEventSender::receiveFinishedSignals(JNIEnv* env) {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName());
+#endif
+
+    ScopedLocalRef<jobject> senderObj(env, NULL);
+    bool skipCallbacks = false;
+    for (;;) {
+        uint32_t publishedSeq;
+        bool handled;
+        status_t status = mInputPublisher.receiveFinishedSignal(&publishedSeq, &handled);
+        if (status) {
+            if (status == WOULD_BLOCK) {
+                return OK;
+            }
+            ALOGE("channel '%s' ~ Failed to consume finished signals.  status=%d",
+                    getInputChannelName(), status);
+            return status;
+        }
+
+        ssize_t index = mPublishedSeqMap.indexOfKey(publishedSeq);
+        if (index >= 0) {
+            uint32_t seq = mPublishedSeqMap.valueAt(index);
+            mPublishedSeqMap.removeItemsAt(index);
+
+#if DEBUG_DISPATCH_CYCLE
+            ALOGD("channel '%s' ~ Received finished signal, seq=%u, handled=%s, "
+                    "pendingEvents=%u.",
+                    getInputChannelName(), seq, handled ? "true" : "false",
+                    mPublishedSeqMap.size());
+#endif
+
+            if (!skipCallbacks) {
+                if (!senderObj.get()) {
+                    senderObj.reset(jniGetReferent(env, mSenderWeakGlobal));
+                    if (!senderObj.get()) {
+                        ALOGW("channel '%s' ~ Sender object was finalized "
+                                "without being disposed.", getInputChannelName());
+                        return DEAD_OBJECT;
+                    }
+                }
+
+                env->CallVoidMethod(senderObj.get(),
+                        gInputEventSenderClassInfo.dispatchInputEventFinished,
+                        jint(seq), jboolean(handled));
+                if (env->ExceptionCheck()) {
+                    ALOGE("Exception dispatching finished signal.");
+                    skipCallbacks = true;
+                }
+            }
+        }
+    }
+}
+
+
+static jint nativeInit(JNIEnv* env, jclass clazz, jobject senderWeak,
+        jobject inputChannelObj, jobject messageQueueObj) {
+    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
+            inputChannelObj);
+    if (inputChannel == NULL) {
+        jniThrowRuntimeException(env, "InputChannel is not initialized.");
+        return 0;
+    }
+
+    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
+    if (messageQueue == NULL) {
+        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
+        return 0;
+    }
+
+    sp<NativeInputEventSender> sender = new NativeInputEventSender(env,
+            senderWeak, inputChannel, messageQueue);
+    status_t status = sender->initialize();
+    if (status) {
+        String8 message;
+        message.appendFormat("Failed to initialize input event sender.  status=%d", status);
+        jniThrowRuntimeException(env, message.string());
+        return 0;
+    }
+
+    sender->incStrong(gInputEventSenderClassInfo.clazz); // retain a reference for the object
+    return reinterpret_cast<jint>(sender.get());
+}
+
+static void nativeDispose(JNIEnv* env, jclass clazz, jint senderPtr) {
+    sp<NativeInputEventSender> sender =
+            reinterpret_cast<NativeInputEventSender*>(senderPtr);
+    sender->dispose();
+    sender->decStrong(gInputEventSenderClassInfo.clazz); // drop reference held by the object
+}
+
+static jboolean nativeSendKeyEvent(JNIEnv* env, jclass clazz, jint senderPtr,
+        jint seq, jobject eventObj) {
+    sp<NativeInputEventSender> sender =
+            reinterpret_cast<NativeInputEventSender*>(senderPtr);
+    KeyEvent event;
+    android_view_KeyEvent_toNative(env, eventObj, &event);
+    status_t status = sender->sendKeyEvent(seq, &event);
+    return !status;
+}
+
+static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jint senderPtr,
+        jint seq, jobject eventObj) {
+    sp<NativeInputEventSender> sender =
+            reinterpret_cast<NativeInputEventSender*>(senderPtr);
+    MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
+    status_t status = sender->sendMotionEvent(seq, event);
+    return !status;
+}
+
+
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit",
+            "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
+            (void*)nativeInit },
+    { "nativeDispose", "(I)V",
+            (void*)nativeDispose },
+    { "nativeSendKeyEvent", "(IILandroid/view/KeyEvent;)Z",
+            (void*)nativeSendKeyEvent },
+    { "nativeSendMotionEvent", "(IILandroid/view/MotionEvent;)Z",
+            (void*)nativeSendMotionEvent },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+int register_android_view_InputEventSender(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/view/InputEventSender",
+            gMethods, NELEM(gMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    FIND_CLASS(gInputEventSenderClassInfo.clazz, "android/view/InputEventSender");
+
+    GET_METHOD_ID(gInputEventSenderClassInfo.dispatchInputEventFinished,
+            gInputEventSenderClassInfo.clazz,
+            "dispatchInputEventFinished", "(IZ)V");
+    return 0;
+}
+
+} // namespace android
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 1ffb1b8..a41a389 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -27,6 +27,8 @@
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
+#include <binder/Parcel.h>
+
 #include <gui/Surface.h>
 #include <gui/SurfaceControl.h>
 #include <gui/GLConsumer.h>
@@ -53,6 +55,7 @@
 static struct {
     jclass clazz;
     jfieldID mNativeObject;
+    jfieldID mNativeObjectLock;
     jfieldID mCanvas;
     jmethodID ctor;
 } gSurfaceClassInfo;
@@ -76,6 +79,9 @@
 
 // ----------------------------------------------------------------------------
 
+// this is just a pointer we use to pass to inc/decStrong
+static const void *sRefBaseOwner;
+
 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
     return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
 }
@@ -85,8 +91,15 @@
 }
 
 sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
-    return reinterpret_cast<Surface *>(
-            env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeObject));
+    sp<Surface> sur;
+    jobject lock = env->GetObjectField(surfaceObj,
+            gSurfaceClassInfo.mNativeObjectLock);
+    if (env->MonitorEnter(lock) == JNI_OK) {
+        sur = reinterpret_cast<Surface *>(
+                env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeObject));
+        env->MonitorExit(lock);
+    }
+    return sur;
 }
 
 jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
@@ -109,7 +122,7 @@
         }
         return NULL;
     }
-    surface->incStrong(surfaceObj);
+    surface->incStrong(&sRefBaseOwner);
     return surfaceObj;
 }
 
@@ -137,18 +150,13 @@
         return 0;
     }
 
-    surface->incStrong(clazz);
+    surface->incStrong(&sRefBaseOwner);
     return int(surface.get());
 }
 
 static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
-    sur->decStrong(clazz);
-}
-
-static void nativeDestroy(JNIEnv* env, jclass clazz, jint nativeObject) {
-    sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
-    sur->decStrong(clazz);
+    sur->decStrong(&sRefBaseOwner);
 }
 
 static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jint nativeObject) {
@@ -309,12 +317,12 @@
     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
     sp<Surface> other(ctrl->getSurface());
     if (other != NULL) {
-        other->incStrong(clazz);
+        other->incStrong(&sRefBaseOwner);
     }
 
     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
     if (sur != NULL) {
-        sur->decStrong(clazz);
+        sur->decStrong(&sRefBaseOwner);
     }
 
     return int(other.get());
@@ -327,14 +335,32 @@
         doThrowNPE(env);
         return 0;
     }
+
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
+    sp<IBinder> binder(parcel->readStrongBinder());
+
+    // update the Surface only if the underlying IGraphicBufferProducer
+    // has changed.
+    if (self != NULL
+            && (self->getIGraphicBufferProducer()->asBinder() == binder)) {
+        // same IGraphicBufferProducer, return ourselves
+        return int(self.get());
+    }
+
+    sp<Surface> sur;
+    sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
+    if (gbp != NULL) {
+        // we have a new IGraphicBufferProducer, create a new Surface for it
+        sur = new Surface(gbp);
+        // and keep a reference before passing to java
+        sur->incStrong(&sRefBaseOwner);
+    }
+
     if (self != NULL) {
-        self->decStrong(clazz);
+        // and loose the java reference to ourselves
+        self->decStrong(&sRefBaseOwner);
     }
-    sp<Surface> sur(Surface::readFromParcel(*parcel));
-    if (sur != NULL) {
-        sur->incStrong(clazz);
-    }
+
     return int(sur.get());
 }
 
@@ -346,7 +372,7 @@
         return;
     }
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
-    Surface::writeToParcel(self, parcel);
+    parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL);
 }
 
 // ----------------------------------------------------------------------------
@@ -356,8 +382,6 @@
             (void*)nativeCreateFromSurfaceTexture },
     {"nativeRelease", "(I)V",
             (void*)nativeRelease },
-    {"nativeDestroy", "(I)V",
-            (void*)nativeDestroy },
     {"nativeIsValid", "(I)Z",
             (void*)nativeIsValid },
     {"nativeIsConsumerRunningBehind", "(I)Z",
@@ -383,6 +407,8 @@
     gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
     gSurfaceClassInfo.mNativeObject =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "I");
+    gSurfaceClassInfo.mNativeObjectLock =
+            env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObjectLock", "Ljava/lang/Object;");
     gSurfaceClassInfo.mCanvas =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
     gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d94d39d..ec10536 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -132,19 +132,19 @@
         jniThrowException(env, OutOfResourcesException, NULL);
         return 0;
     }
-    surface->incStrong(clazz);
+    surface->incStrong((void *)nativeCreate);
     return int(surface.get());
 }
 
 static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
-    ctrl->decStrong(clazz);
+    ctrl->decStrong((void *)nativeCreate);
 }
 
 static void nativeDestroy(JNIEnv* env, jclass clazz, jint nativeObject) {
     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
     ctrl->clear();
-    ctrl->decStrong(clazz);
+    ctrl->decStrong((void *)nativeCreate);
 }
 
 static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 1494bc5..87e339c 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -41,13 +41,13 @@
 
 static jint nativeCreate(JNIEnv* env, jclass clazz) {
     SurfaceComposerClient* client = new SurfaceComposerClient();
-    client->incStrong(clazz);
+    client->incStrong((void*)nativeCreate);
     return reinterpret_cast<jint>(client);
 }
 
 static void nativeDestroy(JNIEnv* env, jclass clazz, jint ptr) {
     SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
-    client->decStrong(clazz);
+    client->decStrong((void*)nativeCreate);
 }
 
 static void nativeKill(JNIEnv* env, jclass clazz, jint ptr) {
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 8a89db5..5baae84 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -109,7 +109,7 @@
     sp<GLConsumer> glConsumer(SurfaceTexture_getSurfaceTexture(env, surface));
     sp<ANativeWindow> window = new Surface(glConsumer->getBufferQueue());
 
-    window->incStrong(0);
+    window->incStrong((void*)android_view_TextureView_createNativeWindow);
     SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
 }
 
@@ -120,7 +120,7 @@
 
     if (nativeWindow) {
         sp<ANativeWindow> window(nativeWindow);
-            window->decStrong(0);
+            window->decStrong((void*)android_view_TextureView_createNativeWindow);
         SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0);
     }
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8a53cc3..8ebc88c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -74,6 +74,11 @@
     <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
 
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DISABLED" />
+    <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLED" />
+
     <protected-broadcast android:name="android.backup.intent.RUN" />
     <protected-broadcast android:name="android.backup.intent.CLEAR" />
     <protected-broadcast android:name="android.backup.intent.INIT" />
@@ -169,6 +174,7 @@
     <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
     <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />
     <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" />
+    <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" />
 
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" />
     <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" />
@@ -610,6 +616,14 @@
         android:label="@string/permlab_installLocationProvider"
         android:description="@string/permdesc_installLocationProvider" />
 
+    <!-- Allows an application to use location features in hardware,
+         such as the geofencing api
+         Protected by signature|system protection level -->
+    <permission android:name="android.permission.LOCATION_HARDWARE"
+        android:permissionGroup="android.permission-group.LOCATION"
+        android:protectionLevel="signature|system" />
+    <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
+
     <!-- ======================================= -->
     <!-- Permissions for accessing networks -->
     <!-- ======================================= -->
@@ -1072,10 +1086,10 @@
 
     <!-- Group of permissions that are related to the screenlock. -->
     <permission-group android:name="android.permission-group.SCREENLOCK"
-        android:label="@string/permgrouplab_storage"
+        android:label="@string/permgrouplab_screenlock"
         android:icon="@drawable/perm_group_screenlock"
         android:permissionGroupFlags="personalInfo"
-        android:description="@string/permgroupdesc_storage"
+        android:description="@string/permgroupdesc_screenlock"
         android:priority="230" />
 
     <!-- Allows applications to disable the keyguard -->
@@ -2187,6 +2201,14 @@
         android:description="@string/permdesc_accessNotifications"
         android:protectionLevel="signature|system" />
 
+    <!-- Must be required by an {@link
+         android.service.notification.NotificationListenerService},
+         to ensure that only the system can bind to it. -->
+    <permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
+        android:label="@string/permlab_bindNotificationListenerService"
+        android:description="@string/permdesc_bindNotificationListenerService"
+        android:protectionLevel="signature" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
@@ -2295,6 +2317,12 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver" >
+            <intent-filter>
+                <action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
@@ -2307,6 +2335,12 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.SELinuxPolicyInstallReceiver" >
+            <intent-filter>
+                <action android:name="android.intent.action.UPDATE_SEPOLICY" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.MasterClearReceiver"
             android:permission="android.permission.MASTER_CLEAR"
             android:priority="100" >
@@ -2324,6 +2358,9 @@
             android:permission="android.permission.MASTER_CLEAR"
             android:exported="true" />
 
+        <service android:name="android.hardware.location.GeofenceHardwareService"
+            android:permission="android.permission.LOCATION_HARDWARE"
+            android:exported="false" />
     </application>
 
 </manifest>
diff --git a/core/res/res/anim/rotation_animation_xfade_exit.xml b/core/res/res/anim/rotation_animation_xfade_exit.xml
index 7300724..1dedde4 100644
--- a/core/res/res/anim/rotation_animation_xfade_exit.xml
+++ b/core/res/res/anim/rotation_animation_xfade_exit.xml
@@ -18,6 +18,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android">
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
-            android:duration="500"
+            android:duration="150"
             android:interpolator="@interpolator/decelerate_quad" />
 </set>
diff --git a/core/res/res/drawable-hdpi/ic_btn_search.png b/core/res/res/drawable-hdpi/ic_btn_search.png
deleted file mode 100644
index 98e61a3..0000000
--- a/core/res/res/drawable-hdpi/ic_btn_search.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search.png b/core/res/res/drawable-hdpi/ic_menu_search.png
index a7f9bbe..ae2f44b 100644
--- a/core/res/res/drawable-hdpi/ic_menu_search.png
+++ b/core/res/res/drawable-hdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png b/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png
index a7f9bbe..420d680 100644
--- a/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_menu_search_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search_holo_light.png b/core/res/res/drawable-hdpi/ic_menu_search_holo_light.png
index 1cb61fa..cc661e3 100644
--- a/core/res/res/drawable-hdpi/ic_menu_search_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_menu_search_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_popup_panel_holo_dark.9.png b/core/res/res/drawable-hdpi/menu_popup_panel_holo_dark.9.png
new file mode 100644
index 0000000..e5ff886
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_popup_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_popup_panel_holo_light.9.png b/core/res/res/drawable-hdpi/menu_popup_panel_holo_light.9.png
new file mode 100644
index 0000000..06d1653
--- /dev/null
+++ b/core/res/res/drawable-hdpi/menu_popup_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_btn_search.png b/core/res/res/drawable-ldpi/ic_btn_search.png
deleted file mode 100644
index bdefbf5..0000000
--- a/core/res/res/drawable-ldpi/ic_btn_search.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_dark.9.png
new file mode 100644
index 0000000..45450e4
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_light.9.png
new file mode 100644
index 0000000..b568989
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_dark.9.png
new file mode 100644
index 0000000..e0434584
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_light.9.png
new file mode 100644
index 0000000..f208c99
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_dark.9.png
new file mode 100644
index 0000000..94eb994
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_light.9.png
new file mode 100644
index 0000000..1fee149
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_dark.9.png
new file mode 100644
index 0000000..7c5826f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_light.9.png
new file mode 100644
index 0000000..974a292
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_focused_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_dark.9.png
new file mode 100644
index 0000000..b3196c9
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_light.9.png
new file mode 100644
index 0000000..1f833d3
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_normal_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_dark.9.png
new file mode 100644
index 0000000..e969abc
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_light.9.png
new file mode 100644
index 0000000..3adbc84
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/quickcontact_badge_overlay_pressed_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_dark.9.png
new file mode 100644
index 0000000..abffc49
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_light.9.png
new file mode 100644
index 0000000..a369081
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_dark.9.png
new file mode 100644
index 0000000..e33e964
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_light.9.png
new file mode 100644
index 0000000..0a845dd
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_dark.9.png
new file mode 100644
index 0000000..74b0352
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_light.9.png
new file mode 100644
index 0000000..bfb4972
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_dark.9.png
new file mode 100644
index 0000000..a321836
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_light.9.png
new file mode 100644
index 0000000..4c5d692
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_focused_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_dark.9.png
new file mode 100644
index 0000000..6199dc5
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_light.9.png
new file mode 100644
index 0000000..1b0905a
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_normal_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_dark.9.png
new file mode 100644
index 0000000..c6d7868
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_light.9.png
new file mode 100644
index 0000000..179644c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/quickcontact_badge_overlay_pressed_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_dark.9.png
new file mode 100644
index 0000000..d253dd4
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_light.9.png
new file mode 100644
index 0000000..65f9ec1
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_dark.9.png
new file mode 100644
index 0000000..105da60
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_light.9.png
new file mode 100644
index 0000000..de53be7
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_dark.9.png
new file mode 100644
index 0000000..3be0b0c
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_light.9.png
new file mode 100644
index 0000000..878c702
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/btn_cab_done_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_dark.9.png
new file mode 100644
index 0000000..039a056
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_light.9.png
new file mode 100644
index 0000000..c8d68c5
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_focused_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_dark.9.png
new file mode 100644
index 0000000..1fef1ad
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_light.9.png
new file mode 100644
index 0000000..6b22d44
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_normal_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png
new file mode 100644
index 0000000..c219527
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_light.9.png b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_light.9.png
new file mode 100644
index 0000000..2a1d508
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/quickcontact_badge_overlay_pressed_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_btn_search.png b/core/res/res/drawable-mdpi/ic_btn_search.png
deleted file mode 100644
index 662f5de..0000000
--- a/core/res/res/drawable-mdpi/ic_btn_search.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search.png b/core/res/res/drawable-mdpi/ic_menu_search.png
index 5d3155e..d18f542 100644
--- a/core/res/res/drawable-mdpi/ic_menu_search.png
+++ b/core/res/res/drawable-mdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png b/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png
index 5d3155e..906da53 100644
--- a/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_menu_search_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search_holo_light.png b/core/res/res/drawable-mdpi/ic_menu_search_holo_light.png
index 2369d03..0350a43 100644
--- a/core/res/res/drawable-mdpi/ic_menu_search_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_menu_search_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_popup_panel_holo_dark.9.png b/core/res/res/drawable-mdpi/menu_popup_panel_holo_dark.9.png
new file mode 100644
index 0000000..2020a42
--- /dev/null
+++ b/core/res/res/drawable-mdpi/menu_popup_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_popup_panel_holo_light.9.png b/core/res/res/drawable-mdpi/menu_popup_panel_holo_light.9.png
new file mode 100644
index 0000000..7cae402
--- /dev/null
+++ b/core/res/res/drawable-mdpi/menu_popup_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_btn_search.png b/core/res/res/drawable-xhdpi/ic_btn_search.png
deleted file mode 100644
index a267c0a..0000000
--- a/core/res/res/drawable-xhdpi/ic_btn_search.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_search.png b/core/res/res/drawable-xhdpi/ic_menu_search.png
index 5c18f9e..4444495 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_search.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_search.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_search_holo_dark.png b/core/res/res/drawable-xhdpi/ic_menu_search_holo_dark.png
index d49c7e2..1208859 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_search_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_search_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_search_holo_light.png b/core/res/res/drawable-xhdpi/ic_menu_search_holo_light.png
index 578cb24..6811782 100644
--- a/core/res/res/drawable-xhdpi/ic_menu_search_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_menu_search_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_popup_panel_holo_dark.9.png b/core/res/res/drawable-xhdpi/menu_popup_panel_holo_dark.9.png
new file mode 100644
index 0000000..e85b0c2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/menu_popup_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_popup_panel_holo_light.9.png b/core/res/res/drawable-xhdpi/menu_popup_panel_holo_light.9.png
new file mode 100644
index 0000000..eea215d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/menu_popup_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/menu_panel_holo_dark.xml b/core/res/res/drawable/menu_panel_holo_dark.xml
new file mode 100644
index 0000000..658a3ac
--- /dev/null
+++ b/core/res/res/drawable/menu_panel_holo_dark.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_above_anchor="true" android:drawable="@android:drawable/menu_popup_panel_holo_dark" />
+    <item android:drawable="@android:drawable/menu_dropdown_panel_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/menu_panel_holo_light.xml b/core/res/res/drawable/menu_panel_holo_light.xml
new file mode 100644
index 0000000..a37e934
--- /dev/null
+++ b/core/res/res/drawable/menu_panel_holo_light.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_above_anchor="true" android:drawable="@android:drawable/menu_popup_panel_holo_light" />
+    <item android:drawable="@android:drawable/menu_dropdown_panel_holo_light" />
+</selector>
diff --git a/core/res/res/layout-xlarge/activity_list.xml b/core/res/res/layout-xlarge/activity_list.xml
index edf6ee6..bf46af8 100644
--- a/core/res/res/layout-xlarge/activity_list.xml
+++ b/core/res/res/layout-xlarge/activity_list.xml
@@ -52,7 +52,8 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
         </LinearLayout>
         <View android:id="@+id/titleDivider"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index 35552d3..59e56af 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -55,7 +55,8 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
         </LinearLayout>
         <ImageView android:id="@+id/titleDivider"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 3f1fa3c..34cb21d 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -53,7 +53,8 @@
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
         </LinearLayout>
         <View android:id="@+id/titleDivider"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/app_not_authorized.xml b/core/res/res/layout/app_not_authorized.xml
new file mode 100644
index 0000000..bd40eeb
--- /dev/null
+++ b/core/res/res/layout/app_not_authorized.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <!-- Customizable description text -->
+    <TextView android:id="@+id/description"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_gravity="start|center_vertical"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip"
+        android:paddingStart="16dip"
+        android:paddingEnd="16dip"
+        android:text="@string/app_no_restricted_accounts"
+    />
+
+    <!-- Horizontal divider line -->
+    <View android:layout_height="1dip"
+        android:layout_width="match_parent"
+        android:background="?android:attr/dividerHorizontal" />
+
+    <!-- Alert dialog style buttons along the bottom. -->
+    <LinearLayout android:id="@+id/button_bar"
+        style="?android:attr/buttonBarStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:measureWithLargestChild="true">
+        <Button android:id="@android:id/button1"
+            style="?android:attr/buttonBarButtonStyle"
+            android:layout_width="wrap_content" android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@android:string/yes"
+            android:onClick="onCancelButtonClicked" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/keyguard_emergency_carrier_area.xml b/core/res/res/layout/keyguard_emergency_carrier_area.xml
index 52adc04..b8a7654 100644
--- a/core/res/res/layout/keyguard_emergency_carrier_area.xml
+++ b/core/res/res/layout/keyguard_emergency_carrier_area.xml
@@ -18,7 +18,7 @@
 -->
 
 <!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<LinearLayout
+<com.android.internal.policy.impl.keyguard.EmergencyCarrierArea
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -29,6 +29,7 @@
     android:clickable="true">
 
     <com.android.internal.policy.impl.keyguard.CarrierText
+        android:id="@+id/carrier_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:singleLine="true"
@@ -72,4 +73,4 @@
             android:visibility="gone"/>
     </LinearLayout>
 
-</LinearLayout>
+</com.android.internal.policy.impl.keyguard.EmergencyCarrierArea>
diff --git a/core/res/res/layout/media_controller.xml b/core/res/res/layout/media_controller.xml
index 7575836..24c2866 100644
--- a/core/res/res/layout/media_controller.xml
+++ b/core/res/res/layout/media_controller.xml
@@ -18,7 +18,8 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="#CC000000"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:layoutDirection="ltr">
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/core/res/res/layout/select_dialog.xml b/core/res/res/layout/select_dialog.xml
index 80d22f6..eb4d8d9 100644
--- a/core/res/res/layout/select_dialog.xml
+++ b/core/res/res/layout/select_dialog.xml
@@ -32,4 +32,5 @@
     android:cacheColorHint="@null"
     android:divider="?android:attr/listDividerAlertDialog"
     android:scrollbars="vertical"
-    android:overScrollMode="ifContentScrolls" />
+    android:overScrollMode="ifContentScrolls"
+    android:textAlignment="viewStart" />
diff --git a/core/res/res/layout/select_dialog_holo.xml b/core/res/res/layout/select_dialog_holo.xml
index 06a5d96..8a92283 100644
--- a/core/res/res/layout/select_dialog_holo.xml
+++ b/core/res/res/layout/select_dialog_holo.xml
@@ -30,4 +30,5 @@
     android:cacheColorHint="@null"
     android:divider="?android:attr/listDividerAlertDialog"
     android:scrollbars="vertical"
-    android:overScrollMode="ifContentScrolls" />
+    android:overScrollMode="ifContentScrolls"
+    android:textAlignment="viewStart" />
diff --git a/core/res/res/layout/simple_expandable_list_item_1.xml b/core/res/res/layout/simple_expandable_list_item_1.xml
index 9810a60..7cce12a 100644
--- a/core/res/res/layout/simple_expandable_list_item_1.xml
+++ b/core/res/res/layout/simple_expandable_list_item_1.xml
@@ -21,4 +21,5 @@
     android:paddingStart="?android:attr/expandableListPreferredItemPaddingLeft"
     android:textAppearance="?android:attr/textAppearanceListItem"
     android:gravity="center_vertical"
+    android:textAlignment="viewStart"
 />
diff --git a/core/res/res/layout/simple_expandable_list_item_2.xml b/core/res/res/layout/simple_expandable_list_item_2.xml
index ed845f8..da60d7a 100644
--- a/core/res/res/layout/simple_expandable_list_item_2.xml
+++ b/core/res/res/layout/simple_expandable_list_item_2.xml
@@ -28,6 +28,7 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="6dip"
         android:textAppearance="?android:attr/textAppearanceListItem"
+        android:textAlignment="viewStart"
     />
 
     <TextView android:id="@android:id/text2"
@@ -36,6 +37,7 @@
         android:layout_below="@android:id/text1"
         android:layout_alignStart="@android:id/text1"
         android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textAlignment="viewStart"
     />
 
 </TwoLineListItem>
diff --git a/core/res/res/layout/wifi_p2p_dialog_row.xml b/core/res/res/layout/wifi_p2p_dialog_row.xml
index ef810a0..2c88b10 100644
--- a/core/res/res/layout/wifi_p2p_dialog_row.xml
+++ b/core/res/res/layout/wifi_p2p_dialog_row.xml
@@ -23,5 +23,6 @@
     <TextView
             android:id="@+id/value"
             style="@style/wifi_item_content"
-            android:textStyle="bold" />
+            android:textStyle="bold"
+            android:textAlignment="viewStart" />
 </LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 8cfad68..ce76d40 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direkte toegang tot die mikrofoon om oudio op te neem."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direkte toegang tot kamera vir die neem van foto of video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Sluitskerm"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Vermoë om die gedrag van die sluitskerm op jou toestel te beïnvloed."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Jou programme-inligting"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Vermoë om die gedrag van ander programme op jou toestel te beïnvloed."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Muurpapier"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"kry toegang tot kennisgewings"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksaksies"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Aan:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer die vereiste PIN in:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Die foon sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Die tablet sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Die foon sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string>
     <string name="select_character" msgid="3365550120617701745">"Voeg karakter in"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Stuur SMS-boodskappe"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; stuur \'n groot aantal SMS-boodskappe. Wil jy hierdie program toelaat om voort te gaan om boodskappe te stuur?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Toeganklikheid"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Muurpapier"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN geaktiveer"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navigeer tuis"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navigeer op"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opsies"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Interne geheue"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwyder"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Moet volume bo veilige vlak verhoog word?"\n"Deur vir lang tydperke op hoë volume te luister, kan jou gehoor beskadig."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Verhoog volume bo aanbevole vlak?"\n"Deur vir lang tydperke teen hoë volume te luister, kan jou gehoor beskadig word."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou aan met twee vingers inhou om toeganklikheid te aktiveer."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Toeganklikheid geaktiveer."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toeganklikheid gekanselleer."</string>
     <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
     <string name="owner_name" msgid="2716755460376028154">"Eienaar"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Hierdie program werk nie met rekeninge vir beperkte gebruikers nie"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Geen program gevind om hierdie handeling te hanteer nie"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2cef636..132d4cc 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"ድምጽ ለመቅረጽ ወደ ማይክሮፎኑ ቀጥተኛ መዳረሻ።"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"ካሜራ"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"ለካሜራ ምስል ወይም ቪዲዮ ለመቅረጽ ቀጥተኛ መዳረሻ።"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"ማያ ገጽ ቆልፍ"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"በመሣሪያዎ ላይ ያለውን የመቆለፊያ ማያ ገጽ ባህሪያት ላይ ተጽዕኖ የመፍጠር ችሎታ።"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"የመተግበሪያዎችህ መረጃ"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"በመሣሪያህ ላይ ያሉ የሌሎች መተግበሪያዎች ባህሪዎች ላይ ተፅዕኖ የማሳረፍ ችሎታ።"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"ልጣፍ"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ከመተግበሪያዎች በተለየ መልኩ እንዴት የአውታረ መረብ አጠቃቀም እንደተመዘገበ ለመቀየር ለመተግበሪያው ይፈቅዳሉ።ለመደበኛ መተግበሪያዎች አገልግሎት አይውልም።"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"ማሳወቂያዎችን ይድረሱ"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ድንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"የፅሁፍ እርምጃዎች"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"የማከማቻ ቦታ እያለቀ ነው"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"አንዳንድ የስርዓት ተግባራት ላይሰሩ ይችላሉ"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"እሺ"</string>
     <string name="cancel" msgid="6442560571259935130">"ይቅር"</string>
     <string name="yes" msgid="5362982303337969312">"እሺ"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"ለ፦"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"የሚፈለገውን ፒን ተይብ፦"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ፒን፦"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"ስልኩ ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ያለው ግንኙነት ይቋረጣል"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ጡባዊው ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ይላቀቃል"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ስልኩ ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ያለው ግንኙነት ይቋረጣል"</string>
     <string name="select_character" msgid="3365550120617701745">"ቁምፊ አስገባ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"የSMS መልዕክቶች መበላክ ላይ"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ቁጥራቸው ብዙ የሆኑ የኤስ.ኤም.ኤስ. መልዕክቶችን እየላከ ነው። ይሄ መተግበሪያ መልዕክቶችን መላኩን እንዲቀጥል መፍቀድ ትፈልጋለህ?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"ተደራሽነት"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ነቅቷል።"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
     <string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት  ንካ።"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"መነሻ ዳስስ"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"አስስ"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ተጨማሪ አማራጮች"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"ውስጣዊ ማከማቻ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD ካርድ"</string>
     <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"ድምጽ አደጋ ከሌለው መጠን በላይ ይጨመር??"\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>
     <string name="user_switched" msgid="3768006783166984410">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
     <string name="owner_name" msgid="2716755460376028154">"ባለቤት"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"ስህተት"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"ይህ መተግበሪያ የተገደቡ ተጠቃሚዎች መለያዎችን አይደግፍም"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"ይህን እርምጃ የሚያከናውን ምንም መተግበሪያ አልተገኘም"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9f6345f..e13c0f2 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"الدخول المباشر إلى الميكروفون لتسجيل الصوت."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"الكاميرا"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"الدخول المباشر إلى الكاميرا لالتقاط صورة أو تصوير مقطع فيديو."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"تأمين الشاشة"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"القدرة على التأثير على سلوك شاشة التأمين في جهازك."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"معلومات التطبيقات"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"القدرة على التأثير في سلوك التطبيقات الأخرى بجهازك."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"الخلفية"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"للسماح للتطبيق بتعديل كيفية حساب استخدام الشبكة في التطبيقات. ليس للاستخدام بواسطة التطبيقات العادية."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"إشعارات الدخول"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"إجراءات النص"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"مساحة التخزين منخفضة"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"قد لا تعمل بعض وظائف النظام"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"موافق"</string>
     <string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
     <string name="yes" msgid="5362982303337969312">"موافق"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"إلى:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"اكتب رقم التعريف الشخصي المطلوب:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"رقم التعريف الشخصي:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"سيتم قطع اتصال الهاتف مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"سيتم قطع اتصال الجهاز اللوحي مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"سيتم قطع اتصال الهاتف مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"إدراج حرف"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"إرسال رسائل قصيرة SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; يرسل عددًا كبيرًا من الرسائل القصيرة SMS. هل تريد السماح لهذا التطبيق بالاستمرار في إرسال الرسائل؟"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"إمكانية الدخول"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"التنقل إلى الشاشة الرئيسية"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"التنقل إلى أعلى"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"المزيد من الخيارات"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"وحدة تخزين داخلية"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"بطاقة SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"وحدة تخزين USB"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"هل تريد رفع مستوى الصوت فوق المستوى الآمن؟"\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>
     <string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"المالك"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"خطأ"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"لا يوفر هذا التطبيق حسابات للمستخدمين المقيّدين"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2c6aff3..6653ac1 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Прамы доступ да мікрафону для запісу гуку."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Прамы доступ да камеры, каб зрабіць здымак ці зняць відэа."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Экран блакіроўкі"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Магчымасць уплываць на паводзіны экрана блакіроўкi на вашай прыладзе."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Інфармацыя аб вашых прыкладаннях"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Магчымасць уплываць на паводзіны іншых прыкладанняў на вашай прыладзе."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Шпалеры"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ да паведамленняў"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дазваляе прыкладанню атрымлiваць, правяраць i выдаляць апавяшчэннi, у тым лiку апублiкаваныя iншымi прыкладаннямi."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Дзеянні з тэкстам"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Месца для захавання на зыходзе"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"ОК"</string>
     <string name="cancel" msgid="6442560571259935130">"Адмяніць"</string>
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Тэлефон будзе часова адключаны ад Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Тэлефон будзе часова адключаны ад сеткі Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Тэлефон будзе часова адключаны ад Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Прыкладанне &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; дасылае вялікую колькасць SMS-паведамленняў. Дазволіць гэтаму прыкладанню працягваць адпраўляць паведамленні?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Спецыяльныя магчымасці"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Шпалеры"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Змена шпалер"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN актываваны"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN актывуецца прыкладаннем <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Дакраніцеся, каб кіраваць сеткай."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Перайсці да пачатковай старонкі"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Перайсці ўверх"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Больш налад"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Унутраная памяць"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\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">"Выдалiць"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Павялiчыць гук больш за рэкамендаваны ўзровень?"\n"Доўгае слуханне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Павялiчыць гук больш за рэкамендаваны ўзровень?"\n"Доўгае слуханне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утрымлiвайце два пальцы, каб уключыць доступ."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Даступнасць уключана."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Даступнасць адменена."</string>
     <string name="user_switched" msgid="3768006783166984410">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Уладальнік"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Памылка"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Гэтае прыкладанне не падтрымлівае уліковыя запісы для карыстальнікаў з абмежаванымі правамі"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Прыкладанне для гэтага дзеяння не знойдзенае"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index f5f89a6..3d3e195 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Осъществяване на директен достъп до микрофона с цел записване на звук."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Осъществяване на директен достъп до камерата с цел заснемане на снимки или видеоклипове."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Заключване на екрана"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Възможност за оказване на влияние върху поведението на заключения екран на устройството ви."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Информация за приложенията ви"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Възможност за оказване на влияние върху поведението на други приложения на устройството ви."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Тапет"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Разрешава на приложението да променя това как употребата на мрежа се отчита спрямо приложенията. Не е предназначено за нормални приложения."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"достъп до известията"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Действия с текста"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Мястото в хранилището е на изчерпване"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Възможно е някои функции на системата да не работят"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Отказ"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"До:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Въведете задължителния ПИН:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ПИН:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Телефонът временно ще прекрати връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Таблетът временно ще прекъсне връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Телефонът временно ще прекрати връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Вмъкване на знак"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Изпращане на SMS съобщения"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; изпраща голям брой SMS съобщения. Искате ли да разрешите на това приложение да продължи да го прави?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Достъпност"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Придвижване към „Начало“"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Придвижване нагоре"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Още опции"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Вътрешно хранилище"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD карта"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"Да се увеличи ли силата на звука над безопасното ниво?"\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>
     <string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Собственик"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Грешка"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Това приложение не поддържа профили за потребители с ограничения"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Няма намерено приложение за извършване на това действие"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index b077308..c96bef8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Accés directe al micròfon per enregistrar àudio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Càmera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Accés directe a la càmera per a la captura d\'imatges o de vídeos."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Bloqueig de pantalla"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Capacitat d\'influir en el comportament de la pantalla de bloqueig al dispositiu."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informació de les aplicacions"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Capacitat d\'afectar el rendiment d\'altres aplicacions del dispositiu."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Fons de pantalla"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permet que l\'aplicació iniciï la IU de confirmació de còpia de seguretat completa. No la pot fer servir qualsevol aplicació."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualitzar finestres no autoritzades"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permet que l\'aplicació creï finestres que utilitzarà la interfície d\'usuari del sistema intern. No indicat per a les aplicacions normals."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"crida d\'altres aplicacions"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"mostra sobre altres aplicacions"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permet que l\'aplicació dibuixi sobre les altres aplicacions o parts de la interfície d\'usuari. Pot interferir amb l\'ús de la interfície a qualsevol aplicació o canviar el que et sembla que estàs veient en altres aplicacions."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar la velocitat d\'animacions global"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permet que l\'aplicació canviï la velocitat d\'animació global (animacions més ràpides o lentes) en qualsevol moment."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet que l\'aplicació modifiqui la manera com es calcula l\'ús de la xarxa per part de les aplicacions. No indicat per a les aplicacions normals."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accedeix a les notificacions"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet que l\'aplicació recuperi, examini i esborri les notificacions, incloses les que han publicat altres aplicacions."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Defineix les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control d\'intents de desbloqueig de pantalla"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Accions de text"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"S\'està acabant l\'espai d\'emmagatzematge"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"D\'acord"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
     <string name="yes" msgid="5362982303337969312">"D\'acord"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Per a:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introdueix el PIN sol·licitat:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"El telèfon es desconnectarà temporalment de la Wi-Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tauleta es desconnectarà temporalment de la Wi-Fi mentre estigui connectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"El telèfon es desconnectarà temporalment de la Wi-Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insereix un caràcter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"S\'estan enviant missatges SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; està enviant molts missatges SMS. Vols permetre que aquesta aplicació continuï enviant missatges?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Torna a la pàgina d\'inici"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Mou cap a dalt"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Més opcions"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Emmagatzematge intern"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Targeta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
@@ -1406,7 +1423,7 @@
     <string name="launchBrowserDefault" msgid="2057951947297614725">"Vols iniciar el navegador?"</string>
     <string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
     <string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
-    <string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una"</string>
+    <string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una vegada"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tauleta"</string>
     <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telèfon"</string>
     <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Auriculars"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Elimina"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vols augmentar el volum per sobre del nivell de seguretat?"\n"Escoltar música a un volum alt durant períodes llargs pot perjudicar l\'oïda."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vols augmentar el volum per sobre del nivell de seguretat?"\n"Escoltar música a un volum alt durant períodes llargs pot danyar l\'oïda."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén premuts els dos dits per activar l\'accessibilitat."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"S\'ha activat l\'accessibilitat."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilitat cancel·lada."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Propietari"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aquesta aplicació no admet comptes per a usuaris limitats"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"No s\'ha trobat cap aplicació per processar aquesta acció"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 3482ed4f..4738834 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Přímý přístup k mikrofonu a možnost nahrávání zvuku"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotoaparát"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Přímý přístup k fotoaparátu a možnost pořizování fotografií a videí"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Obrazovka uzamčení"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Možnost ovlivnit chování obrazovky uzamčení v zařízení."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informace o vašich aplikacích"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Možnost ovlivnit chování dalších aplikací v zařízení"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Tapeta"</string>
@@ -329,8 +331,8 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Umožňuje aplikaci spustit uživatelské rozhraní potvrzení úplné zálohy. Toto oprávnění nesmí používat žádná aplikace."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazení nepovolených oken"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Umožňuje aplikaci vytvářet okna, která se budou používat v interním uživatelském rozhraní systému. Toto oprávnění není určeno pro běžné aplikace."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"kreslení přes další aplikace"</string>
-    <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Umožňuje aplikaci využívat jiné aplikace nebo části uživatelského rozhraní. Aplikace tak může zasahovat do používání rozhraní jakékoli aplikace a měnit rozhraní zobrazené v jiných aplikacích."</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"vykreslení přes další aplikace"</string>
+    <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Umožňuje aplikaci vykreslování nad jinými aplikacemi nebo částmi uživatelského rozhraní. Tato funkce může zasahovat do vašeho používání rozhraní jiné aplikace nebo měnit zobrazovaný obsah v jiných aplikacích."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"změna globální rychlosti animace"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Umožňuje aplikaci kdykoliv globálně změnit rychlost animací (rychlejší či pomalejší animace)."</string>
     <string name="permlab_manageAppTokens" msgid="1286505717050121370">"správa aplikačních tokenů"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikaci upravit způsob výpočtu využití sítě aplikacemi. Toto oprávnění není určeno pro běžné aplikace."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"přístup k oznámením"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikacím načítat, zobrazovat a mazat oznámení včetně těch přidaných jinými aplikacemi."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -885,7 +891,7 @@
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Umožňuje aplikaci číst historii všech adres URL navštívených v Prohlížeči a všechny záložky v Prohlížeči. Poznámka: Pro prohlížeče třetí strany a jiné aplikace umožňující procházení webu toto oprávnění platit nemusí."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"psaní webových záložek a historie"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Umožňuje aplikaci upravit historii prohlížeče nebo záložky uložené v tabletu. Aplikace s tímto oprávněním může vymazat či pozměnit data prohlížeče. Poznámka: Pro prohlížeče třetí strany a jiné aplikace umožňující procházení webu toto oprávnění platit nemusí."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Umožňuje aplikaci upravit historii prohlížeče nebo záložky uložené v telefonu. Aplikace s tímto oprávněním může vymazat či pozměnit data prohlížeče .Poznámka: Pro prohlížeče třetí strany a jiné aplikace umožňující procházení webu toto oprávnění platit nemusí."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Umožňuje aplikaci upravit historii prohlížeče nebo záložky uložené v telefonu. Aplikace s tímto oprávněním může vymazat či pozměnit data prohlížeče. Poznámka: Pro prohlížeče třetí strany a jiné aplikace umožňující procházení webu toto oprávnění platit nemusí."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"nastavení budíku"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Umožňuje aplikaci nastavit budík v nainstalované aplikaci budík. Některé aplikace budík tuto funkci nemusí obsahovat."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"přidat hlasovou zprávu"</string>
@@ -959,7 +965,7 @@
   </plurals>
   <plurals name="in_num_days">
     <item quantity="one" msgid="5413088743009839518">"zítra"</item>
-    <item quantity="other" msgid="5109449375100953247">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+    <item quantity="other" msgid="5109449375100953247">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
   </plurals>
   <plurals name="abbrev_num_seconds_ago">
     <item quantity="one" msgid="1849036840200069118">"před 1 s"</item>
@@ -991,7 +997,7 @@
   </plurals>
   <plurals name="abbrev_in_num_days">
     <item quantity="one" msgid="2178576254385739855">"zítra"</item>
-    <item quantity="other" msgid="2973062968038355991">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+    <item quantity="other" msgid="2973062968038355991">"za <xliff:g id="COUNT">%d</xliff:g> dny"</item>
   </plurals>
     <string name="preposition_for_date" msgid="9093949757757445117">"dne <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"v <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Operace s textem"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"V úložišti je málo místa"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Některé systémové funkce nemusí fungovat"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadejte požadovaný kód PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefon se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;odesílá velký počet SMS zpráv. Chcete aplikaci povolit, aby zprávy odesílala i nadále?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Usnadnění"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Přejít na plochu"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Přejít nahoru"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Další možnosti"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Interní úložiště"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odebrat"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcete hlasitost zvýšit nad bezpečnou úroveň?"\n"Dlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Zvýšit hlasitost nad doporučenou úroveň?"\n"Dlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Usnadnění zapnete dlouhým stisknutím dvěma prsty."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Usnadnění přístupu je aktivováno."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Usnadnění zrušeno."</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Vlastník"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Chyba"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Tato aplikace u omezeného počtu uživatelů nepodporuje účty"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Aplikace potřebná k provedení této akce nebyla nalezena"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 3fb84ec..6c16e56 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -143,7 +143,7 @@
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Ringervibrering"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringeren er aktiveret"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned..."</string>
-    <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tabletcomputer slukkes nu."</string>
+    <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tablet slukkes nu."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon slukkes nu."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slukke?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Genstart i sikker tilstand"</string>
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direkte adgang til mikrofonen, så der kan optages lyd."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direkte adgang til kamera, så der kan tages billeder eller optages video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Lås skærm"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Evne til at påvirke skærmlåsens adfærd på enheden."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Oplysninger om dine applikationer"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Evne til at påvirke andre applikationers adfærd på din enhed."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Baggrund"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Tillader, at appen kan åbne brugergrænsefladen til bekræftelse af komplet sikkerhedskopiering. Må ikke anvendes af nogen app."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserede vinduer"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Tillader, at appen kan oprette vinduer, der er beregnet til brugergrænsefladen i det interne system. Anvendes ikke af normale apps."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"tegne over andre apps"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"trække over andre apps"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Tillader, at appen trækkes oven på andre applikationer eller dele af brugergrænsefladen. De kan forstyrre din brug af grænsefladen i en applikation eller ændre det, du tror, du ser i andre applikationer."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"rediger global animationshastighed"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Tillader, at appen til enhver tid kan ændre den globale animationshastighed (hurtigere eller langsommere animationer)."</string>
@@ -522,7 +524,7 @@
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Tillader, at appen kan slukke og tænde din tablet."</string>
     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Tillader, at appen kan slukke og tænde telefonen."</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"kør i fabriksindstillet testtilstand"</string>
-    <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Kør som en producenttest på lavt niveau, der giver fuld adgang til tabletcomputerens hardware. Kun tilgængeligt når en tabletcomputer kører i producenttesttilstand."</string>
+    <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Kør som en producenttest på lavt niveau, der giver fuld adgang til tabletens hardware. Kun tilgængeligt når en tablet kører i producenttesttilstand."</string>
     <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Kør som en producenttest på lavt niveau. Giver fuld adgang til telefonens hardware. Kun tilgængeligt når en telefon kører i producenttesttilstand."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"angiv tapet"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Tillader, at appen kan konfigurere systembaggrunden."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillader, at appen kan ændre den måde, som netværksforbrug udregnes på i forhold til apps. Anvendes ikke af normale apps."</string>
     <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>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <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>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der er snart ikke mere lagerplads"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nogle systemfunktioner virker måske ikke"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv den påkrævede pinkode:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pinkode:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefonens Wi-Fi-forbindelse vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Wi-Fi-forbindelse til tabletten vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonens Wi-Fi-forbindelse vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sender sms-beskeder"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sender et stort antal sms-beskeder. Vil du tillade, at denne app fortsat sender beskeder?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgængelighed"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapet"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Skift tapet"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Naviger hjem"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Naviger op"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere valgmuligheder"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Internt lager"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto."\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Skal lydstyrken være over det sikre niveau?"\n"Du kan skade din hørelse ved at lytte ved høj lydstyrke i længere tid."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Skal lydstyrken være over det anbefalede niveau?"\n"Du kan skade din hørelse ved at lytte ved høj lydstyrke i længere tid."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hold fortsat to fingre nede for at aktivere tilgængelighed."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tilgængelighed aktiveret."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgængelighed er annulleret."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Ejer"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Fejl"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Denne applikation understøtter ikke konti for brugere med begrænsede rettigheder"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Der blev ikke fundet nogen applikation, der kan håndtere denne handling"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 95e0b5b..ead4004 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direkter Zugriff auf das Mikrofon zur Audioaufnahme"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direkter Zugriff auf Kamera für Bild- oder Videoaufnahmen"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Bildschirm sperren"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Kann die Bildschirmsperre auf Ihrem Gerät beeinflussen"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informationen zu Ihren Apps"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Einflussnahme auf das Verhalten anderer Apps auf Ihrem Gerät"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Hintergrund"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Ermöglicht der App, die Benutzeroberfläche zur Bestätigung der vollständigen Sicherung zu starten. Kann nicht von jeder App verwendet werden."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Nicht autorisierte Fenster anzeigen"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Ermöglicht der App die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Apps vorgesehen."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Über andere Apps zeichnen"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Über anderen Apps einblenden"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Ermöglicht der App, über andere Apps oder Teile der Benutzeroberfläche zu zeichnen. Dies kann sich auf die Oberfläche in jeder App auswirken oder die erwartete Darstellung in anderen Apps verändern."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Ermöglicht der App, die allgemeine Animationsgeschwindigkeit (langsamere oder schnellere Animationen) jederzeit anzupassen."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ermöglicht der App, die Art und Weise zu ändern, wie der Netzwerkverbrauch im Hinblick auf Apps berechnet wird. Nicht für normale Apps vorgesehen."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"Auf Benachrichtigungen zugreifen"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ermöglicht der App das Abrufen, Überprüfen und Löschen von Benachrichtigungen, einschließlich Benachrichtigungen, die von anderen Apps gepostet wurden"</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textaktionen"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Der Speicherplatz wird knapp"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Einige Systemfunktionen funktionieren möglicherweise nicht."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"An:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Geben Sie die erforderliche PIN ein:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Das Telefon wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hergestellt wird."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Das Tablet wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> besteht."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Das Telefon wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hergestellt wird."</string>
     <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS werden gesendet"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sendet eine große Anzahl SMS. Möchten Sie zulassen, dass die App weiterhin Nachrichten sendet?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Bedienungshilfen"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hintergrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviert"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
     <string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Zur Startseite navigieren"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Nach oben navigieren"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Weitere Optionen"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Interner Speicher"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-Karte"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Entfernen"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Lautstärke höher als Schwellenwert stellen?"\n"Wenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Lautstärke über den Schwellenwert anheben?"\n"Wenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Drücken Sie mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Bedienungshilfen aktiviert"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Bedienungshilfen abgebrochen"</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Eigentümer"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Fehler"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Diese App unterstützt keine Konten für eingeschränkte Nutzer."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Für diese Aktion wurde keine App gefunden."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 478b064..ac4ec2e 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Άμεση πρόσβαση στο μικρόφωνο για την εγγραφή ήχου."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Κάμερα"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Άμεση πρόσβαση σε κάμερα για λήψη εικόνας ή βίντεο."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Κλείδωμα οθόνης"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Δυνατότητα επίδρασης της συμπεριφοράς της οθόνης κλειδώματος στη συσκευή σας."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Οι πληροφορίες των εφαρμογών σας"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Δυνατότητα επιρροής συμπεριφοράς άλλων εφαρμογών στη συσκευή σας."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Ταπετσαρία"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Επιτρέπει στην εφαρμογή την τροποποίηση του τρόπου υπολογισμού της χρήσης δικτύου έναντι των εφαρμογών. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"πρόσβαση στις ειδοποιήσεις"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Ενέργειες κειμένου"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ο χώρος αποθήκευσης εξαντλείται"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Ορισμένες λειτουργίες συστήματος ενδέχεται να μην λειτουργούν"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Προς:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Το τηλέφωνο θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Το tablet θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Το τηλέφωνο θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Η εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; στέλνει έναν μεγάλο αριθμό μηνυμάτων SMS. Θέλετε να επιτρέψετε σε αυτήν την εφαρμογή να συνεχίσει να στέλνει μηνύματα;"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Προσβασιμότητα"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Πλοήγηση στην αρχική σελίδα"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Πλοήγηση προς τα επάνω"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Περισσότερες επιλογές"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Εσωτερικός χώρος αποθήκευσης"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Κάρτα SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Χώρος αποθήκευσης USB"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"Αύξηση έντασης ήχου πάνω από το επίπεδο ασφαλείας;"\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>
     <string name="user_switched" msgid="3768006783166984410">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Κάτοχος"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Σφάλμα"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Αυτή η εφαρμογή δεν υποστηρίζει λογαριασμούς για περιορισμένους χρήστες"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Δεν υπάρχει εφαρμογή για τη διαχείριση αυτής της ενέργειας"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 8794a5d..5285532 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direct access to the microphone to record audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direct access to camera for image or video capture."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Lock screen"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Ability to affect behaviour of the lock screen on your device."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Your applications information"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Ability to affect behaviour of other applications on your device."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Wallpaper"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Allows the app to modify how network usage is accounted against apps. Not for use by normal apps."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"access notifications"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Allows the app to retrieve, examine, and clear notifications, including those posted by other apps."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Text actions"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Storage space running out"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Some system functions may not work"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"The phone will temporarily disconnect from Wi-FI while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"The phone will temporarily disconnect from Wi-FI while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insert character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibility"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navigate home"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navigate up"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"More options"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Internal storage"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account."\n\n" Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remove"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Raise volume above safe level?"\n"Listening at high volume for long periods may damage your hearing."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Raise volume above recommended level?"\n"Listening at high volume for long periods may damage your hearing."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Keep holding down two fingers to enable accessibility."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibility enabled."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibility cancelled."</string>
     <string name="user_switched" msgid="3768006783166984410">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Owner"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"This application does not support accounts for limited users"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"No application found to handle this action"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 985b088..20f0c33 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -182,7 +182,7 @@
     <string name="permgroupdesc_bluetoothNetwork" msgid="5625288577164282391">"Acceder a dispositivos y redes a través de Bluetooth"</string>
     <string name="permgrouplab_audioSettings" msgid="8329261670151871235">"Configuración de audio"</string>
     <string name="permgroupdesc_audioSettings" msgid="2641515403347568130">"Cambiar la configuración de audio"</string>
-    <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Afecta la batería."</string>
+    <string name="permgrouplab_affectsBattery" msgid="6209246653424798033">"Afecta la batería"</string>
     <string name="permgroupdesc_affectsBattery" msgid="6441275320638916947">"Uso de las características que se pueden agotar rápidamente la batería"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
     <string name="permgroupdesc_calendar" msgid="5777534316982184416">"Acceso directo a calendario y eventos"</string>
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Acceso directo a micrófono para grabar audio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Cámara"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Acceso directo a cámara para imagen o captura de video"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Bloquear pantalla"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Capacidad para afectar el comportamiento de la pantalla de bloqueo del dispositivo."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Información de tus aplicaciones"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Capacidad para influir en el comportamiento de otras aplicaciones en el dispositivo"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Fondo de pantalla"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permite que la aplicación inicie la IU de confirmación de copia de seguridad completa. No todas las aplicaciones pueden utilizar este permiso."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permite que la aplicación cree ventanas para la interfaz de usuario interna del sistema. Las aplicaciones normales no deben usar este permiso."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"destacar sobre otras aplicaciones"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"mostrar sobre otras aplicaciones"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite a la aplicación escribir por encima de otras aplicaciones o partes de la interfaz de usuario que pueden interferir en tu uso de la interfaz en cualquier aplicación o cambiar lo que crees que ves en otras aplicaciones."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar la velocidad de la animación global"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permite que la aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y elimine notificaciones, incluidas aquellas publicadas por otras aplicaciones."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio de almacenamiento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no estén disponibles."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"El dispositivo se desconectará temporalmente de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tableta se desconectará temporalmente de la red Wi-Fi mientras esté conectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"El dispositivo se desconectará temporalmente de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está enviando una gran cantidad de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Desplazarse hasta la página principal"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Desplazarse hacia arriba"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Almacenamiento interno"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Tarjeta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"¿Aumentar el volumen por encima del nivel seguro?"\n"Si escuchas con el volumen alto durante períodos prolongados, puedes dañar tu audición."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"¿Quieres subir el volumen por encima del nivel recomendado?"\n"Si escuchas música con el volumen alto durante períodos prolongados, puedes dañar tu audición."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén presionado con dos dedos para activar la accesibilidad."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Se activó la accesibilidad."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Se canceló la accesibilidad."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Propietario"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicación no admite cuentas para usuarios restringidos."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"No se encontró una aplicación para manejar esta acción."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index febefe3..7dc03bec 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Acceder directamente al micrófono para grabar audio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Cámara"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Acceder directamente a la cámara para hacer fotos o grabar vídeos"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Pantalla de bloqueo"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Posibilidad de modificar el comportamiento de la pantalla de bloqueo del dispositivo"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Información de tus aplicaciones"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Posibilidad de influir en el funcionamiento de otras aplicaciones del dispositivo"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Fondo de pantalla"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permite que la aplicación inicie la interfaz de usuario de confirmación de copia de seguridad completa. Ninguna aplicación debe usar este permiso."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permite que la aplicación cree ventanas para la interfaz de usuario interna del sistema. Las aplicaciones normales no deben usar este permiso."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"destacar sobre otras aplicaciones"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"mostrar sobre otras aplicaciones"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite que la aplicación escriba sobre otras aplicaciones o en partes de interfaz de usuario. Pueden interferir con el uso de la interfaz en cualquier aplicación o modificar lo que crees que se muestra en otras aplicaciones."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidad de animación global"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permite que la aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que la aplicación modifique cómo se registra el uso de red en relación con las aplicaciones. Las aplicaciones normales no deben usar este permiso."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acceder a las notificaciones"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que la aplicación recupere, examine y borre notificaciones, incluidas las que han publicado otras aplicaciones."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Queda poco espacio"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Es posible que algunas funciones del sistema no funcionen."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"El teléfono se desconectará temporalmente de la red Wi-Fi mientras está conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"El tablet se desconectará temporalmente de la red Wi-Fi mientras esté conectado a  <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"El teléfono se desconectará temporalmente de la red Wi-Fi mientras está conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está enviando un gran número de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Ir al escritorio"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Desplazarse hacia arriba"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Almacenamiento interno"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Tarjeta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminar"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"¿Subir el volumen por encima del nivel de seguridad?"\n"Escuchar sonidos a alto volumen durante largos períodos de tiempo puede dañar tus oídos."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"¿Quieres subir el volumen por encima del nivel recomendado?"\n"Escuchar sonidos a alto volumen durante largos períodos de tiempo puede dañar tus oídos."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén la pantalla pulsada con dos dedos para habilitar las funciones de accesibilidad."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Accesibilidad habilitada"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilidad cancelada"</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Propietario"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicación no admite cuentas de usuarios limitados."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 2815c43..e78e169 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Otsene juurdepääs mikrofonile heli salvestamiseks."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kaamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Otsene juurdepääs kaamerale fotode või videote jäädvustamiseks."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Lukustuskuva"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Võime mõjutada lukustuskuva käitumist seadmes."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Teie rakenduste teave"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Võime mõjutada teiste seadmes olevate rakenduste käitumist."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Taustapilt"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"juurdepääsu märguanded"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Võimaldab rakendusel tuua, kontrollida ja kustutada märguandeid, sh neid, mille on postitanud teised rakendused."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoimingud"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Talletusruum saab täis"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Mõned süsteemifunktsioonid ei pruugi töötada"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Tühista"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Saaja:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefoni ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tahvelarvuti ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefoni ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-sõnumite saatmine"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saadab suurel hulgal SMS-sõnumeid. Kas tahate lubada sellel rakendusel ka edaspidi sõnumeid saata?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Juurdepääsetavus"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Liigu avalehele"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Liigu üles"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Rohkem valikuid"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Sisemine salvestusruum"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eemalda"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Kas suurendada helitugevust üle ohutu piiri?"\n"Pikaajaline suure helitugevusega muusika kuulamine võib kahjustada kuulmist."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Kas suurendada helitugevust üle soovitatud taseme?"\n"Pikaajaline suure helitugevusega muusika kuulamine võib kahjustada kuulmist."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hõlbustuse lubamiseks hoidke kaht sõrme all."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Hõlbustus on lubatud."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hõlbustus on tühistatud."</string>
     <string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Omanik"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Viga"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Rakendus ei toeta piiratud õigustega kasutajate kontosid"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Selle toimingu käsitlemiseks ei leitud ühtegi rakendust"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 660029a..3ab64c0 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"مستقیم به میکروفن برای ضبط صدا دسترسی داشته باشید."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"دوربین"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"مستقیم به دوربین برای عکس گرفتن یا ضبط فیلم دسترسی داشته باشید."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"صفحه قفل"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"امکان تاثیرگذاری بر روی رفتار دستگاه در زمانی که صفحه آن قفل شده است."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"اطلاعات برنامه‌های شما"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"می‌تواند بر عملکرد برنامه‌های دیگر روی دستگاه اثر بگذارد."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"تصویر زمینه"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"به برنامه اجازه می‎دهد تا نحوه محاسبه کاربرد شبکه در برنامه را تغییر دهد. برای استفاده برنامه‎های عادی نیست."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلان‌های دسترسی"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"فضای ذخیره‌سازی رو به اتمام است"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"تأیید"</string>
     <string name="cancel" msgid="6442560571259935130">"لغو"</string>
     <string name="yes" msgid="5362982303337969312">"تأیید"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"به:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"پین لازم را تایپ کنید:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"پین:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"این گوشی به‌طور موقت از Wi-Fi قطع خواهد شد، در حالی که به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> وصل است"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"در حین اتصال به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ارتباط این رایانه لوحی با Wi-Fi موقتاً قطع خواهد شد."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"این گوشی به‌طور موقت از Wi-Fi قطع خواهد شد، در حالی که به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> وصل است"</string>
     <string name="select_character" msgid="3365550120617701745">"درج نویسه"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"ارسال پیامک ها"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; در حال ارسال تعداد زیادی پیامک است. آیا اجازه می‌دهید این برنامه همچنان پیامک ارسال کند؟"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"قابلیت دسترسی"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN فعال شد"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
     <string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"رفتن به صفحهٔ اصلی"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"حرکت به بالا"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"سایر گزینه‌ها"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"حافظهٔ داخلی"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"کارت SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"حافظهٔ USB"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"صدا به بالاتر از سطح ایمن افزایش یابد؟"\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>
     <string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"دارنده"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"خطا"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"این برنامه حساب‌های تعداد محدودی از کاربران را پشتیبانی نمی‌کند"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"برنامه‌ای برای انجام این عملکرد موجود نیست"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 78e1412..86a9fae 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Äänen tallentamiseen käytettävän mikrofonin käyttöoikeus."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Kuvien tai videon tallentamiseen käytettävän kameran käyttöoikeus."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Lukitusruutu"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Lupa vaikuttaa laitteesi lukitusruudun toimintaan."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Sovelluksiesi tiedot"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Mahdollisuus vaikuttaa muiden laitteen sovelluksien käytökseen."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Taustakuva"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Antaa sovelluksen muokata, miten sovellusten verkonkäyttöä lasketaan. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"käytä ilmoituksia"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstitoiminnot"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Tallennustila loppumassa"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kaikki järjestelmätoiminnot eivät välttämättä toimi"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kohde:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Puhelimen yhteys wifi-verkkoon katkaistaan väliaikaisesti puhelimen ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet-laitteen yhteys wifi-verkkoon katkaistaan väliaikaisesti tabletin ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Puhelimen yhteys wifi-verkkoon katkaistaan väliaikaisesti puhelimen ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lähettää suuria määriä tekstiviestejä. Annetaanko tämän sovelluksen jatkaa tekstiviestien lähettämistä?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Esteettömyys"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Siirry etusivulle"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Siirry ylös"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lisää asetuksia"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Sisäinen tallennustila"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kortti"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Poista"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Nostetaanko äänenvoimakkuus turvallista tasoa voimakkaammaksi?"\n"Jos kuuntelet suurella äänenvoimakkuudella pitkiä aikoja, kuulosi voi vahingoittua."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Nostetaanko äänenvoimakkuus suositeltua tasoa voimakkaammaksi?"\n"Jos kuuntelet suurella äänenvoimakkuudella pitkiä aikoja, kuulosi voi vahingoittua."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Ota esteettömyystila käyttöön koskettamalla pitkään kahdella sormella."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Esteettömyystila käytössä."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Esteettömyystila peruutettu."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Omistaja"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Virhe"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Tämä sovellus ei tue rajoitettujen käyttäjien tilejä"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Tätä toimintoa käsittelevää sovellusta ei löydy"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 4c9c0a5..3b539da8 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Accès direct au microphone pour enregistrer du contenu audio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Appareil photo"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Accès direct à la caméra pour la capture d\'images ou de vidéos"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Écran de verrouillage"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Modifier le comportement de l\'écran de verrouillage sur votre appareil"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informations relatives à vos applications"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Possibilité de modifier le comportement des autres applications sur votre appareil"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Fond d\'écran"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permet à l\'application de modifier l\'utilisation du réseau par les autres applications. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accéder aux notifications"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permet aux applications de récupérer, d\'examiner et d\'autoriser les notifications, y compris celles envoyées par d\'autres applications."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -902,7 +908,7 @@
     <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Permettre à l\'application titulaire d\'accéder à des fournisseurs de contenu depuis la commande shell. Les applications standards ne devraient jamais avoir recours à cette autorisation."</string>
     <string name="permlab_updateLock" msgid="3527558366616680889">"déconseiller mises à jour auto appareil"</string>
     <string name="permdesc_updateLock" msgid="1655625832166778492">"Permet à l\'application autorisée d\'indiquer au système le moment opportun pour un redémarrage non interactif en vue de la mise à jour de l\'appareil."</string>
-    <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
+    <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Mémoriser"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Jamais"</string>
@@ -918,7 +924,7 @@
     <string name="searchview_description_query" msgid="5911778593125355124">"Requête de recherche"</string>
     <string name="searchview_description_clear" msgid="1330281990951833033">"Effacer la requête"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Envoyer la requête"</string>
-    <string name="searchview_description_voice" msgid="2453203695674994440">"Recherche vocale"</string>
+    <string name="searchview_description_voice" msgid="2453203695674994440">"Recherche vocale"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activer \"Explorer au toucher\" ?"</string>
     <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec la tablette en effectuant certains gestes."</string>
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> souhaite activer la fonctionnalité \"Explorer au toucher\". Lorsque celle-ci est activée, vous pouvez entendre ou voir les descriptions des éléments que vous sélectionnez, ou bien interagir avec le téléphone en effectuant certains gestes."</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Actions sur le texte"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Espace de stockage bientôt saturé"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Il est possible que certaines fonctionnalités du système ne soient pas opérationnelles."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"À :"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le code PIN requis :"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Code PIN :"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Le téléphone sera déconnecté du réseau Wi-Fi tant qu\'il sera connecté à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tablette sera déconnectée du réseau Wi-Fi tant qu\'elle sera connectée à l\'appareil \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Le téléphone sera déconnecté du réseau Wi-Fi tant qu\'il sera connecté à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envoie un grand nombre de SMS. Autorisez-vous cette application à poursuivre l\'envoi des messages ?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilité"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Retour à l\'accueil"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Parcourir vers le haut"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Plus d\'options"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Mémoire de stockage interne"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Carte SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Supprimer"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Augmenter le volume au-dessus du niveau de sécurité ?"\n"L\'écoute à un volume élevé pendant des périodes prolongées peut endommager votre audition."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Augmenter le volume au-dessus du niveau recommandé ?"\n"L\'écoute à un volume élevé pendant des périodes prolongées peut endommager votre audition."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Pour activer l\'accessibilité, appuyez de manière prolongée avec deux doigts."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"L\'accessibilité a bien été activée."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilité annulée."</string>
     <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"Propriétaire"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Erreur"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Les comptes des utilisateurs en accès limité ne sont pas acceptés pour cette application."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Aucune application trouvée pour gérer cette action."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 3aaace5..ac20919 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"ऑडियो रिकॉर्ड करने के लिए माइक्रोफ़ोन पर सीधी पहुंच."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"कैमरा"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"चित्र या वीडियो कैप्‍चर के लिए कैमरे पर सीधी पहुंच."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"स्‍क्रीन लॉक करें"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"आपके उपकरण की लॉक स्क्रीन का व्यवहार प्रभावित करने की क्षमता."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"आपके एप्‍लिकेशन की जानकारी"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"अपने उपकरण पर अन्‍य एप्‍लिकेशन के व्‍यवहार को प्रभावित करने की क्षमता."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"वॉलपेपर"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"एप्लिकेशन को यह संशोधित करने देता है कि एप्‍लिकेशन की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य एप्‍लिकेशन द्वारा उपयोग करने के लिए नहीं."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचनाओं तक पहुंचें"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"एप्लिकेशन को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य एप्लिकेशन के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्‍क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"पाठ क्रियाएं"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"संग्रहण स्‍थान समाप्‍त हो रहा है"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"ठीक"</string>
     <string name="cancel" msgid="6442560571259935130">"रद्द करें"</string>
     <string name="yes" msgid="5362982303337969312">"ठीक"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"प्रति:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्‍यक पिन लिखें:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"फ़ोन <xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहते समय Wi-Fi से अस्थायी रूप से डिस्कनेक्ट हो जाएगा"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहने पर टेबलेट Wi-Fi से अस्थायी रूप से डिस्कनेक्ट हो जाएगा"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"फ़ोन <xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहते समय Wi-Fi से अस्थायी रूप से डिस्कनेक्ट हो जाएगा"</string>
     <string name="select_character" msgid="3365550120617701745">"वर्ण सम्‍मिलित करें"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS संदेश भेज रहा है"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; बड़ी संख्या में SMS संदेश भेज रहा है. क्या आप इस एप्लिकेशन को संदेश भेजना जारी रखने देना चाहते हैं?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"पहुंच-योग्यता"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
     <string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्‍पर्श करें."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"होम पर नेविगेट करें"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"ऊपर नेविगेट करें"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"अधिक विकल्प"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"आंतरिक संग्रहण"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD कार्ड"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB संग्रहण"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"वॉल्यूम को सुरक्षित स्तर से अधिक करें?"\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>
     <string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"स्वामी"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"त्रुटि"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"यह एप्लिकेशन सीमित उपयोगकर्ताओं के खातों का समर्थन नहीं करता है"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index dbf80ce..9569a6c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Izravan pristup mikrofonu za snimanje zvuka."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotoaparat"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Izravan pristup fotoaparatu za slikanje ili snimanje videozapisa."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Zaključan zaslon"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Mogućnost utjecanja na ponašanje zaključanog zaslona na uređaju."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informacije o vašoj aplikaciji"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Sposobnost da utječu na postupanje drugih aplikacija na vašem uređaju."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Pozadinska slika"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Omogućuje aplikaciji izmjenu načina upotrebe mreže u odnosu na aplikacije. Nije namijenjeno uobičajenim aplikacijama."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obavijestima"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Omogućuje aplikaciji dohvaćanje, pregledavanje i brisanje obavijesti, uključujući obavijesti drugih aplikacija."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje s tekstom"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ponestaje prostora za pohranu"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda neće raditi"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"U redu"</string>
     <string name="cancel" msgid="6442560571259935130">"Odustani"</string>
     <string name="yes" msgid="5362982303337969312">"U redu"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Prima:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Upišite potreban PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefon će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Umetni znak"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje veliki broj SMS poruka. Želite li dopustiti ovoj aplikaciji da nastavi slati poruke?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Dostupnost"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Kreni na početnu"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Kreni gore"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Više opcija"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Interna pohrana"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Pojačati iznad sigurne razine?"\n"Dulje slušanje preglasne glazbe može vam oštetiti sluh."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Želite li pojačati iznad preporučene razine?"\n"Dulje slušanje preglasne glazbe može vam oštetiti sluh."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Nastavite držati s dva prsta kako biste omogućili pristupačnost."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Dostupnost je omogućena."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost otkazana."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Vlasnik"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Pogreška"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aplikacija ne podržava račune za ograničene korisnike"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena aplikacija za upravljanje ovom radnjom"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3cb1df7..61e3707 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Közvetlen hozzáférés a mikrofonhoz hangrögzítés céljából"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fényképezőgép"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Közvetlen hozzáférés a fényképezőgéphez kép vagy videó rögzítése céljából"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Lezárási képernyő"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Képes a lezárási képernyő viselkedésének befolyásolására az eszközön."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Az Ön alkalmazásainak információi"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Képes az eszközön a többi alkalmazás viselkedését befolyásolni."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Háttérkép"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lehetővé teszi az alkalmazás számára annak módosítását, hogy a hálózathasználatot hogyan számolják el az alkalmazások esetében. Normál alkalmazások nem használhatják."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"hozzáférési értesítések"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lehetővé teszi, hogy az alkalmazás értesítéseket kérdezzen le, vizsgáljon és tisztítson meg, beleértve az egyéb alkalmazások által közzétett értesítéseket is."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Műveletek szöveggel"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kevés a szabad terület"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Előfordulhat, hogy néhány rendszerfunkció nem működik."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Mégse"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Címzett:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Adja meg a szükséges PIN kódot:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kód:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"A telefon ideiglenesen kilép a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"A táblagép ideiglenesen lecsatlakozik a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"A telefon ideiglenesen kilép a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik."</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter beszúrása"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-ek küldése"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/ b&gt; nagyszámú SMS üzenetet küld. Engedélyezi, hogy ez az alkalmazás továbbra is üzeneteket küldjön?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Kisegítő lehetőségek"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Háttérkép"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiválva"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Ugrás a főoldalra"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Felfele mozgás"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"További lehetőségek"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Belső tárhely"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kártya"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eltávolítás"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"A biztonságos szint fölé emeli a hangerőt?"\n"Ha hosszú ideig hangosan hallgatja a zenét, az károsíthatja a hallását."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"A javasolt szint fölé emeli a hangerőt?"\n"Ha hosszú ideig hangosan hallgatja a zenét, az károsíthatja a hallását."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Továbbra is tartsa lenyomva két ujját a hozzáférés engedélyezéséhez."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Hozzáférés engedélyezve"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hozzáférés megszakítva."</string>
     <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
     <string name="owner_name" msgid="2716755460376028154">"Tulajdonos"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Hiba"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ez az alkalmazás nem támogatja a korlátozott jogokkal rendelkező felhasználói fiókokat."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nincs megfelelő alkalmazás a művelet elvégzésére."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 33e3b2d..f4664e9 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Akses langsung ke mikrofon untuk merekam audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Akses langsung ke kamera untuk gambar atau tangkapan video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Layar terkunci"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Kemampuan untuk memengaruhi perilaku layar terkunci di perangkat Anda."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informasi aplikasi Anda"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Kemampuan untuk memengaruhi perilaku aplikasi lain pada perangkat Anda."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Wallpaper"</string>
@@ -351,7 +353,7 @@
     <string name="permlab_canRequestEnahncedWebAccessibility" msgid="1905232971331801453">"meminta aksesibilitas web yang disempurnakan"</string>
     <string name="permdesc_canRequestEnahncedWebAccessibility" msgid="4500520989321729676">"Memungkinkan pemegang meminta pengaktifan penyempurnaan aksesibilitas web. Contohnya, memasang skrip agar konten aplikasi lebih mudah diakses."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"mengikat ke layanan SMS"</string>
-    <string name="permdesc_bindTextService" msgid="8151968910973998670">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan teks (mis. SpellCheckerService). Tidak pernah diperlukan oleh apl normal."</string>
+    <string name="permdesc_bindTextService" msgid="8151968910973998670">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan teks (misal: SpellCheckerService). Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"mengikat ke layanan VPN"</string>
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan Vpn. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"mengikat ke wallpaper"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Mengizinkan apl memodifikasi cara penggunaan jaringan diperhitungkan terhadap apl. Tidak untuk digunakan oleh apl normal."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"mengakses pemberitahuan"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Mengizinkan aplikasi mengambil, memeriksa, dan menghapus pemberitahuan, termasuk pemberitahuan yang diposkan oleh aplikasi lain."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang penyimpanan hampir habis"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak dapat bekerja"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Oke"</string>
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
     <string name="yes" msgid="5362982303337969312">"Oke"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ketik PIN yang diminta:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Ponsel akan terputus sementara dari Wi-Fi saat tersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Sambungan tablet akan diputuskan dari Wi-Fi untuk sementara saat tersambung dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Ponsel akan terputus sementara dari Wi-Fi saat tersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisipkan huruf"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Mengirim pesan SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sedang mengirim pesan SMS dalam jumlah besar. Izinkan aplikasi ini untuk melanjutkan pengiriman pesan?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Aksesibilitas"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi ke beranda"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi naik"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsi lainnya"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Penyimpanan internal"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kartu SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Hapus"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Naikkan volume di atas tingkat aman?"\n"Mendengarkan volume tinggi dalam jangka waktu yang lama dapat merusak pendengaran Anda."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Naikkan volume di atas tingkat aman?"\n"Mendengarkan volume tinggi dalam jangka waktu yang lama dapat merusak pendengaran Anda."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tahan terus dua jari untuk mengaktifkan aksesibilitas."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Aksesibilitas diaktifkan."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Aksesibilitas dibatalkan."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Pemilik"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Kesalahan"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aplikasi ini tidak mendukung akun untuk pengguna terbatas"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Tidak ada aplikasi yang ditemukan untuk menangani tindakan ini"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ec9a00e..592492a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Accesso diretto al microfono per registrare audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotocamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Accesso diretto alla fotocamera per acquisizione di immagini o video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Schermata di blocco"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Possibilità di influenzare il comportamento della schermata di blocco sul dispositivo."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informazioni sulle tue applicazioni"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Possibilità di influenzare il comportamento di altre applicazioni sul dispositivo."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Sfondo"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Consente all\'applicazione di avviare l\'interfaccia utente di conferma del backup completo. Non utilizzare per nessuna applicazione."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualizzazione finestre non autorizzate"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Consente all\'applicazione di creare finestre destinate all\'uso da parte dell\'interfaccia utente del sistema interno. Da non usare per normali applicazioni."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"disegno su altre applicazioni"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"spostamento sopra altre app"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Consente all\'applicazione di spostarsi sopra ad altre applicazioni o parti dell\'interfaccia utente. Potrebbe interferire con il tuo utilizzo dell\'interfaccia in qualsiasi applicazione o cambiare ciò che credi di vedere in altre applicazioni."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modifica velocità di animazione globale"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Consente all\'applicazione di modificare la velocità di animazione globale (animazioni più veloci o più lente) in qualsiasi momento."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Consente all\'applicazione di modificare il calcolo dell\'utilizzo della rete tra le applicazioni. Da non usare per normali applicazioni."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesso a notifiche"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Consente all\'app di recuperare, esaminare e cancellare notifiche, comprese quelle pubblicate da altre app."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Azioni testo"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spazio di archiviazione in esaurimento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Alcune funzioni di sistema potrebbero non funzionare"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"A:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Inserisci il PIN richiesto:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Il telefono verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Il tablet verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Il telefono verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sta inviando molti SMS. Vuoi consentire all\'applicazione di continuare a inviare messaggi?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilità"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Vai alla home page"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Vai in alto"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Altre opzioni"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Memoria interna"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Scheda SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Aumentare il volume oltre il livello di sicurezza?"\n"Ascoltare musica ad alto volume per lunghi periodi potrebbe danneggiare l\'udito."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentare il volume oltre il livello di sicurezza?"\n"Ascoltare musica ad alto volume per lunghi periodi potrebbe danneggiare l\'udito."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Continua a tenere premuto con due dita per attivare l\'accessibilità."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Accessibilità attivata."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilità annullata."</string>
     <string name="user_switched" msgid="3768006783166984410">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietario"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Errore"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Questa applicazione non supporta account di utenti con limitazioni"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nessuna applicazione trovata in grado di gestire questa azione"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 6a0d9e2..97c52c5 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"גישה ישירה אל המיקרופון להקלטת אודיו."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"מצלמה"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"גישה ישירה למצלמה לצילום תמונות או וידאו."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"מסך נעילה"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"היכולת להשפיע על אופן ההתנהגות של מסך הנעילה של המכשיר."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"מידע על היישומים שלך"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"יכולת להשפיע על התנהגותם של יישומים אחרים במכשיר."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"טפט"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"הרשאה זו מאפשרת ליישום לשנות את אופן החישוב של נתוני שימוש ברשת מול כל יישום. לא מיועד לשימוש ביישומים רגילים."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"גישה להתראות"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר ליישום לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי יישומים אחרים."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"פעולות טקסט"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"שטח האחסון אוזל"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"ייתכן שפונקציות מערכת מסוימות לא יפעלו"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"אישור"</string>
     <string name="cancel" msgid="6442560571259935130">"ביטול"</string>
     <string name="yes" msgid="5362982303337969312">"אישור"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"אל:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"הקלד את קוד ה-PIN הנדרש."</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"הטלפון יתנתק מרשת ה-Wi-Fi באופן זמני בשעה שהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"הטאבלט יתנתק מרשת ה-Wi-Fi באופן זמני בשעה שהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"הטלפון יתנתק מרשת ה-Wi-Fi באופן זמני בשעה שהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"הוסף תו"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"שולח הודעות SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt; <xliff:g id="APP_NAME">%1$s</xliff:g> &lt;/ b&gt; שולח מספר רב של הודעות SMS. האם ברצונך לאפשר ליישום זה להמשיך לשלוח הודעות?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"נגישות"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN מופעל"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"נווט לדף הבית"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"נווט למעלה"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"אפשרויות נוספות"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"אחסון פנימי"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"כרטיס SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"אחסון USB"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"האם להעלות את עוצמת הקול מעל לרמה הבטוחה?"\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>
     <string name="user_switched" msgid="3768006783166984410">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"בעלים"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"שגיאה"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"היישום הזה לא תומך בחשבונות עבור משתמשים מוגבלים"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"לא נמצא יישום שתומך בפעולה זו"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 5009af4..0abacb1 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"マイクに直接アクセスして音声を記録します。"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"カメラ"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"カメラに直接アクセスして画像または動画を撮影します。"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"ロック画面"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"端末でのロック画面の動作に影響を与えることができます。"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"アプリ情報"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"端末上の他のアプリの動作に影響を及ぼします。"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"壁紙"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"アプリに対するネットワーク利用の計算方法を変更することをアプリに許可します。通常のアプリでは使用しません。"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"通知にアクセス"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"テキスト操作"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"空き容量わずか"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"一部のシステム機能が動作しない可能性があります"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"キャンセル"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"必要なPINを入力してください:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"携帯端末が<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が解除されます。"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"タブレットが<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が切断されます"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"携帯端末が<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が解除されます。"</string>
     <string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;が大量のSMSメッセージを送信しています。このアプリにこのままメッセージの送信を許可しますか?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"ユーザー補助"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPNが有効になりました"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
     <string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"ホームへ移動"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"上へ移動"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"その他のオプション"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"内部ストレージ"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SDカード"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"安全レベルを超えるまで音量を上げますか?"\n"大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"推奨レベルを超えるまで音量を上げますか?"\n"大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ユーザー補助機能を有効にするには2本の指で押し続けてください。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"ユーザー補助が有効になりました。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ユーザー補助をキャンセルしました。"</string>
     <string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
     <string name="owner_name" msgid="2716755460376028154">"所有者"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"エラー"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"このアプリでは限定ユーザー用のアカウントはサポートしていません"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"この操作を行うアプリが見つかりません"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 46e6339..b07878c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"오디오를 녹음하기 위해 마이크에 직접 액세스합니다."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"카메라"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"이미지 및 동영상을 캡처하기 위해 카메라에 직접 액세스합니다."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"화면 잠금"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"기기의 잠금 화면 동작에 영향을 줄 수 있는 기능입니다."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"애플리케이션 정보"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"기기의 다른 애플리케이션의 작동에 영향을 줍니다."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"배경화면"</string>
@@ -259,7 +261,7 @@
     <string name="permdesc_getTasks" msgid="7454215995847658102">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 허용합니다. 이 경우 앱이 기기에서 사용되는 다른 앱에 대한 정보를 검색할 수 있습니다."</string>
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"여러 사용자와의 상호작용"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"앱이 기기에서 다양한 사용자에 대한 작업을 수행할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자 간의 보호를 위반할 수 있습니다."</string>
-    <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이센스"</string>
+    <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이선스"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"여러 사용자와의 가능한 모든 상호작용을 허용합니다."</string>
     <string name="permlab_manageUsers" msgid="1676150911672282428">"사용자 관리"</string>
     <string name="permdesc_manageUsers" msgid="8409306667645355638">"앱이 기기에서 검색, 생성 및 삭제를 포함한 사용자 관리를 할 수 있도록 허용합니다."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"애플리케이션이 애플리케이션의 네트워크 사용량을 계산하는 방식을 수정할 수 있도록 허용합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"알림 액세스"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"텍스트 작업"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"저장 공간이 부족함"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"일부 시스템 기능이 작동하지 않을 수 있습니다."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"확인"</string>
     <string name="cancel" msgid="6442560571259935130">"취소"</string>
     <string name="yes" msgid="5362982303337969312">"확인"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"받는사람:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"필수 PIN 입력:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 휴대전화의 Wi-Fi 연결이 해제됩니다."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 태블릿의 Wi-Fi 연결이 해제됩니다."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 휴대전화의 Wi-Fi 연결이 해제됩니다."</string>
     <string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;이(가) SMS 메시지를 대량으로 보내고 있습니다. 해당 앱이 메시지를 계속 보내도록 하시겠습니까?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"접근성"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
     <string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"홈 탐색"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"위로 탐색"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"옵션 더보기"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"내부 저장소"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 카드"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"안전한 수준 이상으로 볼륨을 높이시겠습니까?"\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>
     <string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
     <string name="owner_name" msgid="2716755460376028154">"소유자"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"오류"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"이 애플리케이션은 제한된 사용자를 위한 계정을 지원하지 않습니다."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"이 작업을 처리하는 애플리케이션을 찾을 수 없습니다."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index fb476b5..1b7b68e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Tiesioginė prieiga prie mikrofono, kad būtų galima įrašyti garsą."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotoaparatas"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Tiesioginė prieiga prie fotoaparato, kad būtų galima fotografuoti vaizdus arba įrašyti vaizdo įrašus."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Užrakinti ekraną"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Galimybė paveikti užrakinimo ekrano veikimą įrenginyje."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Programų informacija"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Galimybė paveikti kitų įrenginio programų veikimą."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Ekrano fonas"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Leidžiama programai keisti, kaip tinklas naudojamas, palyginti su programomis. Neskirta naudoti įprastoms programoms."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pasiekti pranešimus"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Programai leidžiama gauti, patikrinti ir išvalyti pranešimus, įskaitant pranešimus, kuriuos paskelbė kitos programos."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksto veiksmai"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Mažėja laisvos saugyklos vietos"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Kai kurios sistemos funkcijos gali neveikti"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Gerai"</string>
     <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
     <string name="yes" msgid="5362982303337969312">"Gerai"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Skirta:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Įveskite reikiamą PIN kodą:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kodas:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefonas bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Planšetinis kompiuteris bus laikinai atjungtas nuo „Wi-Fi“, kol jis prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonas bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
     <string name="select_character" msgid="3365550120617701745">"Įterpti simbolį"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS pranešimų siuntimas"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Naudojant &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siunčiama daug SMS pranešimų. Ar norite leisti šiai programai toliau siųsti pranešimus?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Pasiekiamumas"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Darbalaukio fonas"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN suaktyvintas"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Naršyti pagrindinį puslapį"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Naršyti į viršų"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Daugiau parinkčių"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Vidinė atmintis"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kortelė"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Pašalinti"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Padidinti garsumą viršijant saugų lygį?"\n"Ilgai klausantis dideliu garsumu gali sutrikti klausa."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Padidinti garsumą viršijant saugų lygį?"\n"Ilgai klausantis dideliu garsumu gali sutrikti klausa."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Laikykite palietę dviem pirštais, kad įgalintumėte pritaikymo neįgaliesiems režimą."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pritaikymas neįgaliesiems įgalintas."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pritaikymo neįgaliesiems režimas atšauktas."</string>
     <string name="user_switched" msgid="3768006783166984410">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Savininkas"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Klaida"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ši programa nepalaiko apribotų naudotojų paskyrų"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nerasta programa šiam veiksmui apdoroti"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 667e29c..9ae5381d 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Tieša piekļuve mikrofonam, lai ierakstītu audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Tieša piekļuve kamerai, lai uzņemtu attēlus vai videoklipus."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Ekrāna bloķēšana"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Spēja ietekmēt bloķēšanas ekrāna darbību jūsu ierīcē."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informācija par jūsu lietojumprogrammām"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Spēja ietekmēt citu ierīcē esošo lietojumprogrammu darbību."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Fona tapete"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ļauj lietotnei mainīt to, kā tīkla lietojums tiek uzskaitīts saistībā ar lietotnēm. Atļauja neattiecas uz parastām lietotnēm."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"piekļuve paziņojumiem"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ļauj lietotnei izgūt, pārbaudīt un dzēst paziņojumus, tostarp lietotņu publicētos paziņojumus."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksta darbības"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Paliek maz brīvas vietas"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Dažas sistēmas funkcijas var nedarboties."</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Labi"</string>
     <string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
     <string name="yes" msgid="5362982303337969312">"Labi"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kam:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ierakstiet pieprasīto PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Tālrunis tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Planšetdators tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Tālrunis tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Ievietojiet rakstzīmi"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Īsziņu sūtīšana"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Lietotne &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sūta daudz īsziņu. Vai vēlaties, lai šī lietotne turpinātu sūtīt ziņojumus?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Pieejamība"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fona tapete"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ir aktivizēts."</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
     <string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Pārvietoties uz sākuma ekrānu"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Pārvietoties augšup"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Vairāk opciju"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Iekšējā atmiņa"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD karte"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">"  — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Noņemt"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vai palielināt skaļumu virs drošības līmeņa?"\n"Ilgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vai palielināt skaļumu virs ieteicamā līmeņa?"\n"Ilgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Lai iespējotu pieejamību, turiet nospiestus divus pirkstus."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pieejamības režīms ir iespējots."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pieejamība ir atcelta."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Īpašnieks"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Kļūda"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Šajā lietojumprogrammā netiek atbalstīti ierobežotu lietotāju konti."</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Netika atrasta neviena lietojumprogramma, kas var veikt šo darbību."</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mcc286/config.xml b/core/res/res/values-mcc286/config.xml
old mode 100755
new mode 100644
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a04aac1..bbde90d 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Akses langsung ke mikrofon untuk merakam audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Akses langsung ke kamera untuk merakam imej atau video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Kunci skrin"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Keupayaan untuk mempengaruhi kelakuan skrin kunci pada peranti anda."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Maklumat aplikasi anda"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Keupayaan untuk mempengaruhi tingkah laku aplikasi lain pada peranti anda."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Kertas dinding"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Membenarkan apl untuk mengubah suai bagaimana penggunaan rangkaian diambil kira terhadap apl. Bukan untuk digunakan oleh apl biasa."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"pemberitahuan akses"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tindakan teks"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ruang storan semakin berkurangan"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Beberapa fungsi sistem mungkin tidak berfungsi"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Batal"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Taipkan PIN yang diperlukan:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Sambungan telefon ke Wi-Fi akan diputuskan buat sementara waktu semasa telefon bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Sambungan tablet ke Wi-Fi akan diputuskan buat sementara waktu semasa tablet bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Sambungan telefon ke Wi-Fi akan diputuskan buat sementara waktu semasa telefon bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Masukkan aksara"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Menghantar mesej SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sedang menghantar banyak mesej SMS. Adakah anda mahu membenarkan apl ini terus menghantar mesej?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Kebolehaksesan"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Kertas dinding"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi laman utama"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi ke atas"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lagi pilihan"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Storan dalaman"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kad SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tingkatkan kelantangan di atas tahap selamat?"\n"Mendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Tingkatkan kelantangan melebihi aras yang dicadangkan?"\n"Mendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Teruskan menahan dengan dua jari untuk mendayakan kebolehcapaian."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Kebolehcapaian didayakan."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Kebolehcapaian dibatalkan."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Pemilik"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Ralat"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Aplikasi ini tidak menyokong akaun untuk pengguna terhad"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Tidak menemui aplikasi untuk mengendalikan tindakan ini"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 62da0ae..3bb5022 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direkte tilgang til mikrofonen for å ta opp lyd."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kameraet"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direkte tilgang til kamera for bilde- eller videoopptak."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Låse skjermen"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Evne til å påvirke atferden til den låste skjermen på enheten din."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Appinformasjonen din"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Ha muligheten til å påvirke andre apper på enheten din."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Bakgrunnen"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Lar appen starte det fullstendige grensesnittet for bekreftelse av sikkerhetskopiering. Skal ikke måtte brukes av noen apper."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserte vinduer"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Lar appen opprette vinduer som er ment for å brukes av brukergrensesnittet til det interne systemet. Ikke beregnet på vanlige apper."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"tegner over andre apper"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"overstyre andre apper"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Lar appen være aktiv over andre apper eller deler av brukergrensesnittet. Dette kan virke inn på bruken din av grensesnittet i andre apper, eller endre det du tror du ser i andre apper."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"endre global animasjonshastighet"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Lar appen når som helst endre den globale animasjonshastigheten (raskere eller langsommere animasjoner)."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Lar appen endre hvordan nettverksbruk regnes ut for apper. Ikke beregnet på vanlige apper."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"varseltilgang"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Lar appen hente, gjennomgå og fjerne varsler, inkludert de som sendes fra andre apper."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksthandlinger"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lite ledig lagringsplass"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Enkelte systemfunksjoner fungerer muligens ikke slik de skal"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv inn påkrevd PIN-kode:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefonen frakobles Wi-Fi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Nettbrettet frakobles Wi-Fi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonen frakobles Wi-Fi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sender et stort antall SMS. Vil du la appen fortsette å sende ut meldinger?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgjengelighet"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Gå til startsiden"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Gå opp"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere alternativer"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Intern lagring"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto."\n\n" Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vil du øke lydnivået over trygt nivå?"\n"Lytting på høyt lydnivå i lange perioder kan skade hørselen din."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vil du øke lydnivået over det anbefalte nivået?"\n"Et høyt lydnivå i lengre perioder kan skade hørselen din."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsett å holde nede to fingre for å aktivere tilgjengelighet."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tilgjengelighet er aktivert."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgjengelighetstjenesten ble avbrutt."</string>
     <string name="user_switched" msgid="3768006783166984410">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Eier"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Feil"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Denne appen støtter ikke kontoer for brukere med begrensninger"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Finner ingen apper som kan utføre denne handlingen"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 47264b0..4d71f08 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Rechtstreeks toegang krijgen tot de microfoon om geluid op te nemen."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Rechtstreeks toegang krijgen tot de camera om afbeeldingen of video\'s vast te leggen."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Scherm vergrendelen"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Mogelijkheid om de werking van het vergrendelingsscherm op uw apparaat te beïnvloeden."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informatie over uw applicaties"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Mogelijkheid om het gedrag van andere applicaties op uw apparaat te beïnvloeden."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Achtergrond"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Hiermee kan een app aanpassen hoe het netwerkgebruik wordt toegekend aan apps. Dit wordt niet gebruikt door normale apps."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"toegang tot meldingen"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Hiermee kan de app meldingen ophalen, onderzoeken en wissen, waaronder meldingen die zijn verzonden door andere apps."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -813,7 +819,7 @@
     <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Gebruikersnaam (e-mail)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
-    <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Aanmelden"</string>
+    <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inloggen"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Gebruikersnaam of wachtwoord ongeldig."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"https://www.google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Controleren…"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tekstacties"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Opslagruimte is bijna vol"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bepaalde systeemfuncties werken mogelijk niet"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1121,7 +1131,7 @@
     <item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item>
   </plurals>
     <string name="wifi_available_sign_in" msgid="4029489716605255386">"Aanmelden bij wifi-netwerk"</string>
-    <string name="network_available_sign_in" msgid="8495155593358054676">"Aanmelden bij netwerk"</string>
+    <string name="network_available_sign_in" msgid="8495155593358054676">"Inloggen bij netwerk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met Wi-Fi"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Naar:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer de gewenste pincode in:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pincode"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl de telefoon verbonden is met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl de telefoon is verbonden met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl de telefoon verbonden is met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; verzendt moment een groot aantal sms-berichten. Wilt u toestaan ​​dat deze app berichten blijft verzenden?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Toegankelijkheid"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Achtergrond"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN is geactiveerd"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navigeren naar startpositie"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Omhoog navigeren"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opties"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Interne opslag"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
@@ -1447,10 +1464,10 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u inloggen op uw Google-account."</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikersnaam (e-mail)"</string>
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Wachtwoord"</string>
-    <string name="kg_login_submit_button" msgid="5355904582674054702">"Aanmelden"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Inloggen"</string>
     <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikersnaam of wachtwoord."</string>
     <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="1052685197710252395">"Account controleren…"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Wilt u het volume verhogen tot boven het aanbevolen geluidsniveau?"\n"Te lang luisteren op een te hoog volume kan leiden tot gehoorbeschadiging."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Wilt u het volume verhogen tot boven het aanbevolen geluidsniveau?"\n"Te lang luisteren op een te hoog volume kan leiden tot gehoorbeschadiging."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Blijf het scherm met twee vingers aanraken om toegankelijkheid in te schakelen."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Toegankelijkheid ingeschakeld."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toegankelijkheid geannuleerd."</string>
     <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Eigenaar"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Deze app ondersteunt geen accounts voor beperkte gebruikers"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Er is geen app gevonden om deze actie uit te voeren"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 98d7477..f4fe466 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Bezpośredni dostęp do mikrofonu i nagrywanie dźwięku."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Aparat"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Bezpośredni dostęp do aparatu – robienie zdjęć i nagrywanie filmów."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Ekran blokady"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Możliwość wpływania na zachowanie ekranu blokady urządzenia."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informacje o aplikacjach"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Możliwość zmiany działania innych aplikacji na urządzeniu."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Tapeta"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pozwala aplikacji na zmienianie sposobu rozliczania wykorzystania sieci przez aplikacje. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostęp do powiadomień"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umożliwia aplikacji pobieranie, sprawdzanie i usuwanie powiadomień, także tych, które pochodzą z innych aplikacji."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
@@ -742,7 +748,7 @@
     <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Partner życiowy"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"Ojciec"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"Znajomy"</string>
-    <string name="relationTypeManager" msgid="6365677861610137895">"Kierownik"</string>
+    <string name="relationTypeManager" msgid="6365677861610137895">"Menedżer"</string>
     <string name="relationTypeMother" msgid="4578571352962758304">"Matka"</string>
     <string name="relationTypeParent" msgid="4755635567562925226">"Rodzic"</string>
     <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Działania na tekście"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Kończy się miejsce"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektóre funkcje systemu mogą nie działać"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Do:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Wpisz wymagany kod PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Kod PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> telefon zostanie tymczasowo odłączony od Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tablet zostanie tymczasowo odłączony od Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> telefon zostanie tymczasowo odłączony od Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wysyła wiele SMS-ów. Chcesz pozwolić tej aplikacji dalej wysyłać SMS-y?"</string>
@@ -1188,7 +1199,7 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Po włączeniu nośnika USB niektóre używane aplikacje zostaną zatrzymane i mogą być niedostępne do chwili jego wyłączenia."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Operacja USB zakończona niepowodzeniem"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Podłączono jako urządzenie multimedialne."</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Podłączono urządzenie multimedialne"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Podłączono jako aparat."</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Podłączono jako nośnik instalacyjny."</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Podłączono akcesorium USB"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Ułatwienia dostępu"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
@@ -1320,7 +1333,7 @@
     <string name="sync_really_delete" msgid="2572600103122596243">"Usuń elementy."</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Cofnij usunięcia"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Nie wykonuj teraz żadnych czynności."</string>
-    <string name="choose_account_label" msgid="5655203089746423927">"Wybierz konto."</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"Wybierz konto"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Dodaj konto"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj konto"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Zwiększ"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Przejdź do strony głównej"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Przejdź wyżej"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Więcej opcji"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Pamięć wewnętrzna"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Usuń"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcesz ustawić głośność powyżej bezpiecznego poziomu?"\n"Słuchanie przy dużym poziomie głośności przez dłuższy czas może doprowadzić do uszkodzenia słuchu."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Chcesz ustawić głośność powyżej bezpiecznego poziomu?"\n"Słuchanie przy dużym poziomie głośności przez dłuższy czas może doprowadzić do uszkodzenia słuchu."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Aby włączyć ułatwienia dostępu, przytrzymaj dwa palce."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Włączono ułatwienia dostępu."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ułatwienia dostępu zostały anulowane."</string>
     <string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Właściciel"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Błąd"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ta aplikacja nie obsługuje kont użytkowników z ograniczeniami"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nie znaleziono aplikacji do obsługi tej akcji"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5a701a0..36751b1 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Acesso direto ao microfone para gravar áudio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmara"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Acesso direto à câmara para captura de imagens ou vídeos."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Bloquear ecrã"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Capacidade de influenciar o comportamento do ecrã de bloqueio no seu dispositivo."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"As informações das suas aplicações"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Capacidade de afetar o comportamento de outras aplicações no seu dispositivo."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Imagem de fundo"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permite que a aplicação inicie a IU de confirmação de cópia de segurança completa. Não deve ser utilizado por qualquer aplicação."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"apresentar janelas não autorizadas"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permite que a aplicação crie janelas que se destinam a ser utilizadas ​​pela interface de utilizador do sistema interno. Nunca é necessário para aplicações normais."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"desenhar sobre outras aplicações"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"mostrar sobre outras aplicações"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite que a aplicação se sobreponha a outras aplicações ou partes da interface de utilizador. Poderá interferir na utilização da interface de qualquer aplicação ou alterar o que pensa estar a ver noutras aplicações."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidade global da animação"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permite que a aplicação altere a velocidade global da animação (animações mais rápidas ou mais lentas) em qualquer altura."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que a aplicação modifique o modo como a utilização da rede é contabilizada em relação a aplicações. Nunca é necessário para aplicações normais."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"aceder às notificações"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que a aplicação obtenha, examine e limpe notificações, incluindo as que foram publicadas por outras aplicações."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acções de texto"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Está quase sem espaço de armazenamento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema poderão não funcionar"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduza o PIN solicitado:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"O telemóvel irá desligar-se temporariamente da rede Wi-Fi enquanto está ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"O tablet sera temporariamente desligado da rede Wi-Fi enquanto estiver ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"O telemóvel irá desligar-se temporariamente da rede Wi-Fi enquanto está ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está a enviar um grande número de mensagens SMS. Pretende autorizar que a aplicação continue a enviar mensagens?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagem de fundo"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navegar para página inicial"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navegar para cima"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"memória de armazenamento interno"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" - "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Aumentar o volume acima do nível de segurança?"\n"Ouvir em volume alto durante longos períodos de tempo poderá prejudicar a sua audição."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentar o volume acima do nível recomendado?"\n"Ouvir em volume alto durante longos períodos de tempo poderá prejudicar a sua audição."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha os dois dedos para ativar a acessibilidade."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
     <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietário"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Erro"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicação não suporta contas de utilizadores limitados"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Não foram encontradas aplicações para executar esta ação"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9eb11b2..61716fe 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Acesso direto ao microfone para gravação de áudio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Acesso direto à câmera para captura de imagens ou vídeo."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Tela de bloqueio"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Capacidade de afetar o comportamento da tela de bloqueio no dispositivo."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informações sobre seus aplicativos"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Capacidade de afetar o comportamento de outros aplicativos no dispositivo."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Plano de fundo"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permite que o aplicativo lance a interface de usuário de confirmação de backup completo. Não deve ser usado por qualquer aplicativo."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"exibir janelas não autorizadas"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permite que o aplicativo crie janelas destinadas ao uso ​​pela interface interna do sistema. Não deve ser usado em aplicativos normais."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"induzir outros aplicativos"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"sobrepor outros aplicativos"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite que o aplicativo se sobreponha visualmente a outros aplicativos ou a partes da interface do usuário. Podem interferir com o uso da interface de qualquer aplicativo ou alterar o que você acha que está vendo em outros aplicativos."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modificar velocidade de animação global"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permite que o aplicativo altere a velocidade de animação global (animação mais rápida ou mais lenta) a qualquer momento."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite que o aplicativo modifique como o uso da rede é contabilizado em relação aos aplicativos. Não deve ser usado em aplicativos normais."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"acessar notificações"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controle o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Ações de texto"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Pouco espaço de armazenamento"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Algumas funções do sistema podem não funcionar"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"O telefone desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"O tablet desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"O telefone desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envia uma grande quantidade de mensagens SMS. Deseja permitir que este aplicativo continue enviando mensagens?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navegar na página inicial"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navegar para cima"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Armazenamento interno"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Cartão SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
@@ -1410,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">"Telefone"</string>
     <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Fones de ouvido"</string>
-    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Alto-falantes do dock"</string>
+    <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Alto-falantes da dock"</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">"Áudio Bluetooth"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Remover"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Aumentar o volume acima do nível seguro?"\n"A audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Aumentar o volume acima do nível recomendado?"\n"A audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietário"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Erro"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"O aplicativo não suporta contas para usuários limitados"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nenhum aplicativo encontrado para executar a ação"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index b49854a..ba863cb 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -271,6 +271,10 @@
     <skip />
     <!-- no translation found for permgroupdesc_camera (2933667372289567714) -->
     <skip />
+    <!-- no translation found for permgrouplab_screenlock (8275500173330718168) -->
+    <skip />
+    <!-- no translation found for permgroupdesc_screenlock (7067497128925499401) -->
+    <skip />
     <!-- no translation found for permgrouplab_appInfo (8028789762634147725) -->
     <skip />
     <!-- no translation found for permgroupdesc_appInfo (3950378538049625907) -->
@@ -1036,6 +1040,10 @@
     <skip />
     <!-- no translation found for permdesc_accessNotifications (458457742683431387) -->
     <skip />
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
     <skip />
     <!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
@@ -1630,6 +1638,10 @@
     <skip />
     <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
     <skip />
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Interrumper"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1777,6 +1789,8 @@
     <skip />
     <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
     <skip />
+    <!-- no translation found for wifi_p2p_frequency_conflict_message (8012981257742232475) -->
+    <skip />
     <!-- no translation found for wifi_p2p_frequency_conflict_message (7363907213787469151) -->
     <skip />
     <string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string>
@@ -1979,6 +1993,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Agids d\'access"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fund davos"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Midar il fund davos"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <!-- no translation found for vpn_title (19615213552042827) -->
     <skip />
     <!-- no translation found for vpn_title_long (6400714798049252294) -->
@@ -2168,6 +2184,10 @@
     <skip />
     <!-- no translation found for action_menu_overflow_description (2295659037509008453) -->
     <skip />
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <!-- no translation found for storage_internal (4891916833657929263) -->
     <skip />
     <!-- no translation found for storage_sd_card (3282948861378286745) -->
@@ -2368,7 +2388,7 @@
     <skip />
     <!-- no translation found for kg_reordering_delete_drop_target_text (7899202978204438708) -->
     <skip />
-    <!-- no translation found for safe_media_volume_warning (7382971871993371648) -->
+    <!-- no translation found for safe_media_volume_warning (7324161939475478066) -->
     <skip />
     <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
     <skip />
@@ -2381,4 +2401,12 @@
     <!-- no translation found for owner_name (2716755460376028154) -->
     <!-- no translation found for owner_name (3879126011135546571) -->
     <skip />
+    <!-- no translation found for error_message_title (4510373083082500195) -->
+    <skip />
+    <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
+    <skip />
+    <!-- no translation found for app_not_found (3429141853498927379) -->
+    <skip />
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index eb7185f..003f932 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -40,7 +40,7 @@
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Serviciul a fost activat pentru:"</string>
     <string name="serviceDisabled" msgid="1937553226592516411">"Serviciul a fost dezactivat."</string>
     <string name="serviceRegistered" msgid="6275019082598102493">"Înregistrarea a reuşit."</string>
-    <string name="serviceErased" msgid="1288584695297200972">"Ştergerea a reuşit."</string>
+    <string name="serviceErased" msgid="1288584695297200972">"Ștergerea a reuşit."</string>
     <string name="passwordIncorrect" msgid="7612208839450128715">"Parolă incorectă."</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI finalizat."</string>
     <string name="badPin" msgid="9015277645546710014">"Codul PIN vechi introdus nu este corect."</string>
@@ -129,8 +129,8 @@
     <string name="contentServiceSync" msgid="8353523060269335667">"Sincronizare"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
-    <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ştergeţi câteva fişiere pentru a elibera spaţiu."</string>
-    <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ştergeţi câteva fişiere pentru a elibera spaţiu."</string>
+    <string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
+    <string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
     <string name="me" msgid="6545696007631404292">"Eu"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opţiuni tablet PC"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Acces direct la microfon pentru înregistrări audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera foto"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Acces direct la camera foto pentru a realiza fotografii şi videoclipuri."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Blocare ecran"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Capacitatea de a afecta comportamentul ecranului de blocare pe dispozitivul dvs."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informaţiile despre aplicaţiile dvs."</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Capacitatea de a influenţa comportamentul altor aplicaţii de pe dispozitiv."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Imaginea de fundal"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Permite aplicaţiei să modifice modul în care este calculată utilizarea reţelei pentru aplicaţii. Nu se utilizează de aplicaţiile obişnuite."</string>
     <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>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <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>
@@ -628,9 +634,9 @@
     <string name="policydesc_resetPassword" msgid="605963962301904458">"Editaţi parola de deblocare a ecranului."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Blocaţi ecranul"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Stabiliţi modul şi timpul în care se blochează ecranul."</string>
-    <string name="policylab_wipeData" msgid="3910545446758639713">"Ştergere integrală date"</string>
-    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ştergeţi datele de pe tabletă fără avertisment, efectuând resetarea configurării din fabrică."</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ştergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică."</string>
+    <string name="policylab_wipeData" msgid="3910545446758639713">"Ștergere integrală date"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Ștergeţi datele de pe tabletă fără avertisment, efectuând resetarea configurării din fabrică."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Ștergeţi datele din telefon fără avertisment, efectuând resetarea configurării din fabrică."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Setaţi serverul proxy global pentru dispozitiv"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Setaţi serverul proxy global pentru dispozitiv care să fie utilizat cât timp politica este activă. Numai primul administrator al dispozitivului poate seta serverul proxy global activ."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"Expirare parolă blocare ecran"</string>
@@ -916,7 +922,7 @@
     <string name="search_go" msgid="8298016669822141719">"Căutaţi"</string>
     <string name="searchview_description_search" msgid="6749826639098512120">"Căutaţi"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"Interogare de căutare"</string>
-    <string name="searchview_description_clear" msgid="1330281990951833033">"Ştergeţi interogarea"</string>
+    <string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeţi interogarea"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
     <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activaţi Exploraţi prin atingere?"</string>
@@ -1036,16 +1042,20 @@
     <string name="copy" msgid="2681946229533511987">"Copiaţi"</string>
     <string name="paste" msgid="5629880836805036433">"Inseraţi"</string>
     <string name="replace" msgid="5781686059063148930">"Înlocuiţi..."</string>
-    <string name="delete" msgid="6098684844021697789">"Ştergeţi"</string>
+    <string name="delete" msgid="6098684844021697789">"Ștergeţi"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Copiaţi adresa URL"</string>
     <string name="selectTextMode" msgid="1018691815143165326">"Selectaţi text"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selectare text"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Adăugaţi în dicţionar"</string>
-    <string name="deleteText" msgid="6979668428458199034">"Ştergeţi"</string>
+    <string name="deleteText" msgid="6979668428458199034">"Ștergeţi"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acţiuni pentru text"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spaţiul de stocare aproape ocupat"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcţii de sistem să nu funcţioneze"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Anulaţi"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1056,7 +1066,7 @@
     <string name="capital_off" msgid="6815870386972805832">"DEZACTIVAT"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Finalizare acţiune utilizând"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acţiune."</string>
-    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ştergeţi setările prestabilite din Setări de sistem &gt; Aplicaţii &gt; Descărcate."</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ștergeţi setările prestabilite din Setări de sistem &gt; Aplicaţii &gt; Descărcate."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Alegeţi o acţiune"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Alegeţi o aplicaţie pentru dispozitivul USB"</string>
     <string name="noApplications" msgid="2991814273936504689">"Această acţiune nu poate fi efectuată de nicio aplicaţie."</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Către:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la reţeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectată la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la reţeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trimite un număr mare de mesaje SMS. Permiteţi acestei aplicaţii să trimită în continuare mesaje?"</string>
@@ -1200,8 +1211,8 @@
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formataţi"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeţi pentru a dezactiva depanarea USB."</string>
-    <string name="select_input_method" msgid="4653387336791222978">"Alegeţi metoda de introducere"</string>
-    <string name="configure_input_methods" msgid="9091652157722495116">"Configurare metode introducere"</string>
+    <string name="select_input_method" msgid="4653387336791222978">"Alegeți metoda de introducere de text"</string>
+    <string name="configure_input_methods" msgid="9091652157722495116">"Setați metode introducere text"</string>
     <string name="use_physical_keyboard" msgid="6203112478095117625">"Tastatură fizică"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Selectaţi aspectul tastaturii"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilitate"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Atingeţi pentru a gestiona reţeaua."</string>
@@ -1317,7 +1330,7 @@
     <string name="gpsVerifNo" msgid="1146564937346454865">"Nu"</string>
     <string name="sync_too_many_deletes" msgid="5296321850662746890">"Limita pentru ştergere a fost depăşită"</string>
     <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> (de) elemente şterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriţi să faceţi?"</string>
-    <string name="sync_really_delete" msgid="2572600103122596243">"Ştergeţi elementele"</string>
+    <string name="sync_really_delete" msgid="2572600103122596243">"Ștergeţi elementele"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Anulaţi aceste ştergeri"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Nu trebuie să luaţi nicio măsură deocamdată"</string>
     <string name="choose_account_label" msgid="5655203089746423927">"Alegeţi un cont"</string>
@@ -1341,7 +1354,7 @@
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduceţi valoarea pentru an"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anulaţi"</string>
-    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ştergeţi"</string>
+    <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Terminat"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Schimbarea modului"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Navigaţi la ecranul de pornire"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navigaţi în sus"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mai multe opţiuni"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Stocare internă"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Card SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ridicaţi volumul mai sus de nivelul sigur?"\n"Ascultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ridicați volumul mai sus de nivelul recomandat?"\n"Ascultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Menţineţi două degete pe ecran pentru a activa accesibilitatea."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilitatea a fost anulată"</string>
     <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Proprietar"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Eroare"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Această aplicație nu acceptă conturile pentru utilizatori cu permisiuni limitate"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Nicio aplicație pentru gestionarea acestei acțiuni"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index b8b1c29..2c8dfe8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Прямой доступ к микрофону для записи звука."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Прямой доступ к камере для фото- и видеосъемки."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Блокировка экрана"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Возможность управлять блокировкой экрана на устройстве."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Информация о приложениях"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Возможность влиять на поведение других приложений на устройстве."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Обои"</string>
@@ -329,7 +331,7 @@
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Приложение сможет отображать окно подтверждения полного резервного копирования. Это разрешение не предназначено для всех приложений."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"показывать неавторизованные окна"</string>
     <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Приложение сможет создавать окна для интерфейса внутренней системы. Это разрешение не используется обычными приложениями."</string>
-    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Показ сообщений поверх других окон"</string>
+    <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Показ элементов интерфейса поверх других окон"</string>
     <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Разрешает приложению отображать элементы своего интерфейса поверх окон других программ. Это может мешать вашему взаимодействию с другими приложениями и вести к недоразумениям."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"изменять глобальную скорость анимации"</string>
     <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Приложение сможет в любой момент изменить общую скорость анимации."</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Приложение сможет изменять порядок расчета использования сетевых ресурсов различными программами. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"доступ к уведомлениям"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
@@ -1046,14 +1052,18 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Операции с текстом"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Заканчивается свободное место"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некоторые системные функции могут не работать"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"ОК"</string>
     <string name="cancel" msgid="6442560571259935130">"Отмена"</string>
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
     <string name="no" msgid="5141531044935541497">"Отмена"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Внимание"</string>
     <string name="loading" msgid="7933681260296021180">"Загрузка…"</string>
-    <string name="capital_on" msgid="1544682755514494298">"ВКЛ"</string>
-    <string name="capital_off" msgid="6815870386972805832">"ВЫКЛ"</string>
+    <string name="capital_on" msgid="1544682755514494298">"I"</string>
+    <string name="capital_off" msgid="6815870386972805832">"O"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Что использовать?"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"По умолчанию для этого действия"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Удаляет настройки по умолчанию в меню \"Настройки &gt; Приложения &gt; Загруженные\"."</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введите PIN-код:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон будет временно отключаться от сети Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> планшетный ПК будет временно отключаться от сети Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон будет временно отключаться от сети Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Введите символ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; отправляет большое количество SMS. Разрешить приложению и дальше отправлять сообщения?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Спец. возможности"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Сеть VPN активна"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Перейти на главную"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Перейти вверх"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Ещё"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Внутренняя память"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
@@ -1465,10 +1482,15 @@
     <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> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google."\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="7382971871993371648">"Увеличить громкость до небезопасного уровня?"\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>
     <string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Владелец"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Ошибка"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Приложение не поддерживает аккаунты с ограниченным доступом"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Невозможно обработать это действие"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c1d2c46..80a2c31 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Priamy prístup k mikrofónu na záznam zvuku."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotoaparát"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Priamy prístup k fotoaparátu na nasnímanie fotografií alebo natočenie videí."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Uzamknúť obrazovku"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Možnosť ovplyvniť správanie zámky obrazovky na vašom zariadení."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Informácie o vašich aplikáciách"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Schopnosť ovplyvniť správanie ďalších aplikácií na vašom zariadení."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Tapeta"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Umožňuje aplikácii upraviť používanie siete jednotlivými aplikáciami. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"prístup k upozorneniam"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Operácie s textom"</string>
     <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>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadajte požadovaný kód PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefón bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi-Fi dočasne odpojený."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi-Fi dočasne odpojený."</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefón bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi-Fi dočasne odpojený."</string>
     <string name="select_character" msgid="3365550120617701745">"Vkladanie znakov"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Odosielanie správ SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikácia &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; posiela veľký počet správ SMS. Chcete tejto aplikácií povoliť, aby aj naďalej posielala správy?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Zjednodušenie"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Sieť VPN je aktivovaná"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Prejsť na plochu"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Prejsť na"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Viac možností"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Interné úložisko"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Karta SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrániť"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcete zvýšiť hlasitosť nad bezpečnú úroveň?"\n"Dlhodobé počúvanie pri vysokej hlasitosti môže viesť k poškodeniu vášho sluchu."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Zvýšiť hlasitosť nad odporúčanú úroveň?"\n"Dlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Zjednodušenie ovládania povolíte dlhým stlačením dvoma prstami."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Zjednodušenie ovládania je povolené."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Zjednodušenie ovládania bolo zrušené."</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Vlastník"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Chyba"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Táto aplikácia nepodporuje účty v prípade používateľov s obmedzením"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Aplikácia potrebná na spracovanie tejto akcie sa nenašla"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 7eb8583..766b605 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Neposreden dostop do mikrofona za snemanje zvoka."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotoaparat"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Neposreden dostop do fotoaparata za fotografiranje ali snemanje videoposnetkov."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Zaklepanje zaslona"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Lahko vpliva na delovanje zaklepanja zaslona v napravi."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Podatki o vaših aplikacijah"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Zmožnost vpliva na delovanje drugih aplikacij v napravi."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Slika za ozadje"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Programu omogoča, da spremeni uporabo omrežja na podlagi programov. Ni za uporabo z navadnimi programi."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"dostop do obvestil"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dovoli aplikaciji, da prenese, razišče in izbriše obvestila, tudi tista, ki so jih objavile druge aplikacije."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Besedilna dejanja"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za shranjevanje bo pošel"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Nekatere sistemske funkcije morda ne delujejo"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"V redu"</string>
     <string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
     <string name="yes" msgid="5362982303337969312">"V redu"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Za:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Vnesite zahtevano kodo PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefon bo začasno prekinil povezavo z Wi-Fi-jem, ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablični računalnik bo začasno prekinil povezavo z Wi-Fi-jem, medtem ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon bo začasno prekinil povezavo z Wi-Fi-jem, ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Vstavljanje znaka"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Pošiljanje sporočil SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pošilja veliko SMS-ov. Ali želite dovoliti, da jih še naprej pošilja?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Pripomočki za osebe s posebnimi potrebami"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Krmarjenje domov"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Krmarjenje navzgor"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Več možnosti"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Notranji pomnilnik"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kartica SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Želite povečati glasnost nad varno raven?"\n"Dolgotrajna izpostavljenost glasnim tonom lahko poškoduje sluh."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Želite povečati glasnost nad varno raven?"\n"Dolgotrajna izpostavljenost glasnemu predvajanju lahko poškoduje sluh."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Če želite omogočiti pripomočke za ljudi s posebnimi potrebami, na zaslonu pridržite z dvema prstoma."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pripomočki za ljudi s posebnimi potrebami so omogočeni."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Omogočanje pripomočkov za ljudi s posebnimi potrebami preklicano."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Lastnik"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Napaka"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ta aplikacija ne podpira računov za uporabnike z omejitvami"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Najdena ni bila nobena aplikacija za izvedbo tega dejanja"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index de942ea..15b9ec5 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Директан приступ микрофону за снимање звука."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Директан приступ камери за снимање слика или видео снимака."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Закључавање екрана"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Могућност да утиче на понашање закључаног екрана на уређају."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Информације о апликацијама"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Способност да се утиче на понашање других апликација на уређају."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Позадина"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозвољава апликацији да измени начин на који апликације користе мрежу. Не користе је уобичајене апликације."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"приступ обавештењима"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Простор за складиштење је на измаку"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Потврди"</string>
     <string name="cancel" msgid="6442560571259935130">"Откажи"</string>
     <string name="yes" msgid="5362982303337969312">"Потврди"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Коме:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Унесите потребни PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Телефон ће привремено прекинути везу са Wi-Fi-јем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Таблет ће привремено прекинути везу са Wi-Fi-јем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Телефон ће привремено прекинути везу са Wi-Fi-јем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Уметање знака"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Слање SMS порука"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; шаље велики број SMS порука. Желите ли да дозволите овој апликацији да настави са слањем порука?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Приступачност"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Кретање до Почетне"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Кретање нагоре"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Још опција"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Интерна меморија"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD картица"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"Желите да појачате звук изнад безбедног нивоа?"\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>
     <string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Власник"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Грешка"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ова апликација не подржава налоге за кориснике са ограничењем"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Није пронађена ниједна апликација која би могла да обави ову радњу"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index adfc22a..291681c 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direktåtkomst till mikrofonen för att spela in ljud."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direktåtkomst till kamera för att ta bilder eller spela in video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Låsa skärmen"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Möjlighet att påverka funktionen för enhetens låsskärm."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Information i dina appar"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Kan påverka beteendet hos andra appar på enheten."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Bakgrund"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Tillåter att appen ändrar hur nätverksanvändning redovisas för appar. Används inte av vanliga appar."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"få åtkomst till meddelanden"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Tillåter att appen hämtar, granskar och raderar meddelanden, även sådana som skickats av andra appar."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
@@ -751,7 +757,7 @@
     <string name="relationTypeSister" msgid="1735983554479076481">"Syster"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Make/maka"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Anpassad"</string>
-    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Startsida"</string>
+    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Hem"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Arbete"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Övrigt"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ange PIN-kod"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Textåtgärder"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Lagringsutrymmet börjar ta slut"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Det kan hända att vissa systemfunktioner inte fungerar"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Till:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ange den obligatoriska PIN-koden:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kod:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Mobilen kommer tillfälligt att kopplas från Wi-Fi när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Surfplattans Wi-Fi-anslutning kommer tillfälligt att avbrytas när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Mobilen kommer tillfälligt att kopplas från Wi-Fi när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; skickar ett stort antal SMS. Vill du tillåta att appen fortsätter att skicka meddelanden?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Visa startsidan"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Navigera uppåt"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Internminne"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ta bort"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vill du höja volymen över den säkra nivån?"\n"Om du lyssnar på hög volym under långa perioder kan din hörsel skadas."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Vill du höja volymen över den rekommenderade nivån?"\n"Om du lyssnar på hög volym under långa perioder kan din hörsel skadas."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsätt trycka med två fingrar om du vill aktivera tillgänglighetsläget."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tillgänglighetsläget har aktiverats."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Byte till tillgänglighetsläge avbrutet."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Ägare"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Fel"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Appen har inte stöd för användarkonton med begränsningar"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Ingen app som kan hantera åtgärden hittades"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index f30d11f..c8f1343 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Kufikia moja kwa moja kipokea sauti ili kurekodi sauti."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Kufikia moja kwa moja kamera ya kunasa taswira au video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Funga skrini"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Uwezo wa kuathiri tabia ya skrini iliyofungwa kwenye kifaa chako."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Taarifa ya programu zako"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Uwezo wa kuathiri tabia ya programu nyingine kwenye kifaa chako."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Taswira"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Huruhusu programu kurekebisha jinsi matumizi ya mtandao yana hesabika dhidi ya programu. Sio ya matumizi na programu za kawaida."</string>
     <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>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <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>
@@ -637,7 +643,7 @@
     <string name="policydesc_expirePassword" msgid="1729725226314691591">"Dhibiti ni mara ngapi nenosiri la kufunga skrini linafaa libadilishwe."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Weka msimbo fiche wa hifadhi"</string>
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Inahitaji kwamba data ya programu iliyohifadhiwa iwe na msimbo fiche."</string>
-    <string name="policylab_disableCamera" msgid="6395301023152297826">"Lemaza kamera"</string>
+    <string name="policylab_disableCamera" msgid="6395301023152297826">"Zima kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zuia matumizi yote ya kamera za kifaa."</string>
     <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"Lemaza vipengele kwenye kilinzi cha kitufe."</string>
     <string name="policydesc_disableKeyguardFeatures" msgid="3467082272186534614">"Inazuia matumizi ya baadhi ya vipengele kwenye kilinzi cha kitufe."</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Vitendo vya maandishi"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhafadhi inakwisha"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Sawa"</string>
     <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
     <string name="yes" msgid="5362982303337969312">"Sawa"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kwa:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Charaza PIN inayohitajika:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Simu itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Kompyuta ndogo itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Simu itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Ingiza kibambo"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Inatuma ujumbe wa SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; inatuma idadi kubwa ya SMS. Je, unataka kuruhusu programu hii kuendelea kutuma SMS?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Ufikiaji"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
@@ -1345,7 +1358,7 @@
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Imefanyika"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
-    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ingiza"</string>
+    <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Chagua programu"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Shiriki na"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Shiriki na <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Abiri nyumbani"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Ongoza"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Chaguo zaidi"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Hifadhi ya mfumo"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Kadi ya SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string>
@@ -1429,7 +1446,7 @@
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Tenganisha"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
-    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Ruwaza Isiyo sahihi"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Mchoro Usio sahihi"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Nenosiri Lisilo sahihi"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN isiyo sahihi"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Jaribu tena baada ya sekunde <xliff:g id="NUMBER">%d</xliff:g>."</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe."\n\n" Jaribu tena baada ya sekunde <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">"Ondoa"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ongeza sauti zaidi ya kiwango salama? "\n"Kusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Iongeza sauti zaidi ya kiwango kinachopendekezwa?"\n"Kusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Endelea kushikilia chini kwa vidole vyako viwili ili kuwezesha ufikivu."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Ufikivu umewezeshwa."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ufikivu umeghairiwa."</string>
     <string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Mmiliki"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Hitilafu"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Programu hii haiwezi kutumiwa na akaunti za watumiaji waliowekewa vizuizi"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Hakuna programu iliyopatikana ili kushughulikia kitendo hiki"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1a6d610..66b3199 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -154,9 +154,9 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
-    <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
+    <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานบั๊ก"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานบั๊ก"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานบั๊กจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"โหมดปิดเสียง"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ปิดเสียงไว้"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"เปิดเสียงแล้ว"</string>
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"เข้าถึงไมโครโฟนเพื่อบันทึกเสียงโดยตรง"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"กล้องถ่ายรูป"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"เข้าถึงกล้องถ่ายรูปเพื่อดูภาพและวิดีโอที่ถ่ายไว้โดยตรง"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"ล็อกหน้าจอ"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"ความสามารถในการส่งผลกระทบต่อพฤติกรรมของหน้าจอล็อกบนอุปกรณ์"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"ข้อมูลแอปพลิเคชันของคุณ"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"สามารถส่งผลต่อการทำงานของแอปพลิเคชันอื่นในอุปกรณ์ของคุณ"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"วอลเปเปอร์"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"อนุญาตให้แอปพลิเคชันแก้ไขวิธีการบันทึกบัญชีการใช้งานเครือข่ายของแอปพลิเคชัน ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"เข้าถึงการแจ้งเตือน"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"การทำงานของข้อความ"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"พื้นที่จัดเก็บเหลือน้อย"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"บางฟังก์ชันระบบอาจไม่ทำงาน"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"ตกลง"</string>
     <string name="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
     <string name="yes" msgid="5362982303337969312">"ตกลง"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"ถึง:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"พิมพ์ PIN ที่ต้องการ:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"โทรศัพท์จะยกเลิกการเชื่อมต่อกับ Wi-Fi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"แท็บเล็ตนี้จะยกเลิกการเชื่อมต่อกับ Wi-Fi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"โทรศัพท์จะยกเลิกการเชื่อมต่อกับ Wi-Fi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"ใส่อักขระ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"กำลังส่งข้อความ SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; กำลังส่งข้อความ SMS จำนวนมาก คุณต้องการอนุญาตให้แอปพลิเคชันนี้ส่งข้อความต่อหรือไม่"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"การเข้าถึง"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"นำทางไปหน้าแรก"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"นำทางขึ้น"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"ตัวเลือกเพิ่มเติม"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"ที่จัดเก็บข้อมูลภายใน"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"การ์ด SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"เพิ่มระดับเสียงจนเกินระดับที่ปลอดภัยหรือไม่"\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>
     <string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="owner_name" msgid="2716755460376028154">"เจ้าของ"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"ข้อผิดพลาด"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"แอปพลิเคชันนี้ไม่สนับสนุนบัญชีผู้ใช้ที่ถูกจำกัด"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"ไม่พบแอปพลิเคชันสำหรับการทำงานนี้"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1354129..bd5f99d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Direktang access sa mikropono upang mag-record ng audio."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Direktang access sa camera para sa pagkuha ng larawan o video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"I-lock ang screen"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Kakayahang maapektuhan ang pagkilos ng lock screen sa iyong device."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Ang impormasyon ng iyong mga application"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Kakayahang maapektuhan ang pag-uugali ng iba pang mga application sa iyong device."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Wallpaper"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Pinapayagan ang app na baguhin kung paano isinasaalang-alang ang paggamit ng network laban sa apps. Hindi para sa paggamit ng normal na apps."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"i-access ang mga notification"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Pinapayagan ang app na kumuha, sumuri, at mag-clear ng mga notification, kabilang ang mga na-post ng iba pang apps."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Pagkilos ng teksto"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nauubusan na ang puwang ng storage"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Maaaring hindi gumana nang tama ang ilang paggana ng system"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kay:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"I-type ang kinakailangang PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Pansamantalang madidiskoneta ang telepono sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Pansamantalang madidiskoneta ang tablet sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Pansamantalang madidiskoneta ang telepono sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Magpasok ng character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Nagpapadala ng mga SMS na mensahe"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ay nagpapadala ng maraming mensaheng SMS. Gusto mo bang payagan ang app na ito na magpatuloy sa pagpapadala ng mga mensahe?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Kakayahang Ma-access"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Naka-activate ang VPN"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Magnabiga sa home"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Magnabiga pataas"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Higit pang mga pagpipilian"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Panloob na storage"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD card"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Lakasan ang volume nang lagpas sa ligtas na antas?"\n"Maaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Lakasan ang volume nang lagpas sa ligtas na antas?"\n"Maaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Panatilihing nakapindot nang matagal ang iyong dalawang daliri upang paganahin ang pagiging naa-access."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pinagana ang accessibility."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Nakansela ang pagiging naa-access."</string>
     <string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"May-ari"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Hindi sinusuportahan ng application na ito ang mga account para sa mga limitadong user"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Walang nakitang application na mangangasiwa sa pagkilos na ito"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index aa3244c..79c3706 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Ses kaydetmek için mikrofona doğrudan erişim."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Resim ve video kaydı için kameraya doğrudan erişim."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Kilit ekranı"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Cihazınızdaki kilit ekranının çalışma biçimini etkileyebilme özelliği."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Uygulama bilgileriniz"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Cihazınızdaki diğer uygulamaların davranışlarını etkileyebilme."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Duvar Kağıdı"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Uygulamaya, ağın uygulamalara göre nasıl kullanılacağını değiştirme izni verir. Normal uygulamalar tarafından kullanılmak için değildir."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"bildirimlere eriş"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Uygulamanın bildirimler almasına, bildirimleri incelemesine ve temizlemesine izin verir. Buna diğer uygulamalar tarafından yayınlanan bildirimler de dahildir."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Metin eylemleri"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Depolama alanı bitiyor"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Bazı sistem işlevleri çalışmayabilir"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"Tamam"</string>
     <string name="cancel" msgid="6442560571259935130">"İptal"</string>
     <string name="yes" msgid="5362982303337969312">"Tamam"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Alıcı:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gerekli PIN\'i yazın:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çok sayıda SMS mesajı gönderiyor. Bu uygulamanın mesaj göndermeye devam etmesine izin veriyor musunuz?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Erişebilirlik"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Ana sayfaya git"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Yukarı git"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Diğer seçenekler"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Dahili depolama birimi"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD kart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Kaldır"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ses düzeyi güvenli seviyenin üzerine çıkarılsın mı?"\n"Yüksek sesle uzun süre dinlemek işitme yetinize zarar verebilir."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Ses düzeyi önerilen seviyenin üzerine çıkarılsın mı?"\n"Uzun süre yüksek sesle dinlemek işitme duyunuza zarar verebilir."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Erişilebilirliği etkinleştirmek için iki parmağınızı basılı tutmaya devam edin."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Erişilebilirlik etkinleştirildi."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erişilebilirlik iptal edildi."</string>
     <string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Sahibi"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Hata"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Bu uygulama, kısıtlı kullanıcı hesaplarını desteklemiyor"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Bu eylemi gerçekleştirecek bir uygulama bulunamadı"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 2f6d65c..ad206d3 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Безпосередній доступ до мікрофона для запису звуку."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Безпосередній доступ до камери для здійснення фото- чи відеозйомки."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Екран блокування"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Можливість впливати на поведінку екрана блокування вашого пристрою."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Інформація про програми"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Здатність впливати на роботу інших програм на пристрої."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Фоновий малюнок"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дозволяє програмі змінювати метод підрахунку того, як програми використовують мережу. Не для використання звичайними програмами."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"отримувати доступ до сповіщень"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Дії з текстом"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Закінчується пам’ять"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Деякі системні функції можуть не працювати"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Скасувати"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введіть потрібний PIN-код:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон тимчасово від’єднається від мережі Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> планшетний ПК тимчасово від’єднається від мережі Wi-Fi"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон тимчасово від’єднається від мережі Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Вставл-ня символу"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Надсил. SMS повідомлень"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Програма &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; надсилає велику кількість SMS-повідомлень. Дозволити цій програмі й надалі надсилати повідомлення?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Доступність"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Перейти на головну"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Перейти вгору"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Інші варіанти"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Внутрішня пам’ять"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Карта SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"Збільшити гучність понад безпечний рівень?"\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>
     <string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Власник"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Помилка"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ця програма не підтримує облікові записи для обмежених користувачів"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Не знайдено програму для обробки цієї дії"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index df86597..4022f04 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Truy cập trực tiếp vào micrô để ghi âm."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Máy ảnh"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Truy cập trực tiếp vào máy ảnh để chụp ảnh hoặc quay video."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Khóa màn hình"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Có thể ảnh hưởng đến thao tác của màn hình khóa trên thiết bị của bạn."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Thông tin về các ứng dụng của bạn"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Khả năng ảnh hưởng tới hoạt động của các ứng dụng khác trên thiết bị của bạn."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Hình nền"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Cho phép ứng dụng sửa đổi cách tính mức sử dụng mạng so với ứng dụng. Không dành cho các ứng dụng thông thường."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"truy cập thông báo"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Cho phép ứng dụng truy xuất, kiểm tra và xóa thông báo, bao gồm những thông báo được đăng bởi các ứng dụng khác."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Tác vụ văn bản"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Sắp hết dung lượng lưu trữ"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Một số chức năng hệ thống có thể không hoạt động"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Hủy"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Người nhận:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Nhập PIN bắt buộc:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Mã PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Điện thoại sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi điện thoại được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Máy tính bảng sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi máy tính bảng được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Điện thoại sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi điện thoại được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Chèn ký tự"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Đang gửi tin nhắn SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; đang gửi rất nhiều tin nhắn SMS. Bạn có muốn cho phép ứng dụng này tiếp tục gửi tin nhắn không?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Khả năng truy cập"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"Đã kích hoạt VPN"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Điều hướng về trang chủ"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Điều hướng lên trên"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Tùy chọn khác"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Bộ nhớ trong"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Thẻ SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Xóa"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tăng âm lượng trên mức an toàn?"\n"Nghe ở âm lượng cao trong thời gian dài có thể gây hại cho thính giác của bạn."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Tăng âm lượng trên mức được đề xuất?"\n"Nghe ở mức âm lượng cao trong thời gian dài có thể gây hại cho thính giác của bạn."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tiếp tục giữ hai ngón tay để bật trợ năng."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Trợ năng đã được bật."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Đã hủy trợ năng."</string>
     <string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Chủ sở hữu"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Lỗi"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Ứng dụng này không hỗ trợ tài khoản cho người dùng giới hạn"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Không tìm thấy ứng dụng nào để xử lý tác vụ này"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 554c1aa..5ebd3c7 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"直接使用麦克风以录制音频。"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"相机"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"直接使用相机以拍摄图片或视频。"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"锁定屏幕"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"影响设备的锁定屏幕。"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"您的应用信息"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"能够影响设备上其他应用的行为。"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"壁纸"</string>
@@ -428,9 +430,9 @@
     <string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允许该应用读取您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
     <string name="permlab_writeProfile" msgid="907793628777397643">"修改您自己的名片"</string>
     <string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允许该应用更改或添加您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
-    <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"读取您的社交视频流"</string>
+    <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"读取您的社交信息流"</string>
     <string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允许该应用访问并同步您和朋友的社交动态信息。在分享信息时一定要小心,因为此权限可让该应用读取您与社交网络上的朋友之间的交流信息。"</string>
-    <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"写入您的社交视频流"</string>
+    <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"写入您的社交信息流"</string>
     <string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"允许该应用显示您朋友的社交动态信息。在分享信息时一定要小心,因为此权限可让该应用冒充某个朋友编写消息。请注意:此权限可能不适用于所有社交网络。"</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"读取日历活动和机密信息"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"允许该应用读取您平板电脑上存储的所有日历活动,包括朋友或同事的活动。此权限可让该应用分享或保存您的日历数据,而不论这些数据是否属于机密或敏感内容。"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允许该应用修改对于各应用的网络使用情况的统计方式。普通应用不应使用此权限。"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"查看通知"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -870,9 +876,9 @@
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
     <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
     <string name="autofill_province" msgid="2231806553863422300">"省/直辖市/自治区"</string>
-    <string name="autofill_postal_code" msgid="4696430407689377108">"邮政编码"</string>
+    <string name="autofill_postal_code" msgid="4696430407689377108">"邮编"</string>
     <string name="autofill_state" msgid="6988894195520044613">"州"</string>
-    <string name="autofill_zip_code" msgid="8697544592627322946">"邮政编码"</string>
+    <string name="autofill_zip_code" msgid="8697544592627322946">"邮编"</string>
     <string name="autofill_county" msgid="237073771020362891">"郡"</string>
     <string name="autofill_island" msgid="4020100875984667025">"岛"</string>
     <string name="autofill_district" msgid="8400735073392267672">"地区"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"文字操作"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"存储空间不足"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"某些系统功能可能无法正常使用"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"确定"</string>
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
     <string name="yes" msgid="5362982303337969312">"确定"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件人:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"键入所需的 PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"手机连接到<xliff:g id="DEVICE_NAME">%1$s</xliff:g>时会暂时断开与 Wi-Fi 的连接。"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"平板电脑连接到“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”时会暂时断开与 Wi-Fi 的连接"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"手机连接到<xliff:g id="DEVICE_NAME">%1$s</xliff:g>时会暂时断开与 Wi-Fi 的连接。"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字符"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在发送大量短信。是否允许该应用继续发送短信?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"辅助功能"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
@@ -1347,8 +1360,8 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"选择应用"</string>
-    <string name="shareactionprovider_share_with" msgid="806688056141131819">"共享对象"</string>
-    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"与“<xliff:g id="APPLICATION_NAME">%s</xliff:g>”共享"</string>
+    <string name="shareactionprovider_share_with" msgid="806688056141131819">"分享方式"</string>
+    <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"使用<xliff:g id="APPLICATION_NAME">%s</xliff:g>分享"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"滑动手柄。触摸并按住。"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
     <string name="description_direction_down" msgid="5087739728639014595">"向下滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"导航首页"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"向上导航"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多选项"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"内存设备"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 卡"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 存储器"</string>
@@ -1399,7 +1416,7 @@
     <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 指纹:"</string>
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"查看全部"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"选择活动"</string>
-    <string name="share_action_provider_share_with" msgid="5247684435979149216">"分享对象"</string>
+    <string name="share_action_provider_share_with" msgid="5247684435979149216">"分享方式"</string>
     <string name="status_bar_device_locked" msgid="3092703448690669768">"设备已锁定。"</string>
     <string name="list_delimeter" msgid="3975117572185494152">"、 "</string>
     <string name="sending" msgid="3245653681008218030">"正在发送..."</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"将音量调高到安全级别以上?"\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>
     <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="owner_name" msgid="2716755460376028154">"机主"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"错误"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"此应用不支持受限用户的帐户"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"找不到可处理此操作的应用"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c13cdf7..a0c8c05 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"直接使用麥克風錄音。"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"相機"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"直接使用相機拍照或錄影。"</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"鎖定畫面"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"可影響裝置的鎖定畫面運作方式。"</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"您的應用程式資訊"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"影響裝置上其他應用程式的行為。"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"桌布"</string>
@@ -506,7 +508,7 @@
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"允許應用程式啟用/停用來自無線電的位置更新通知 (不建議一般應用程式使用)。"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"存取登機選項"</string>
-    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"允許讀取/寫入由簽入服務上載的內容 (不建議一般應用程式使用)。"</string>
+    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"允許讀取/寫入由簽入服務上傳的內容 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindGadget" msgid="776905339015863471">"選擇小工具"</string>
     <string name="permdesc_bindGadget" msgid="8261326938599049290">"允許應用程式告知系統哪個應用程式可以使用哪些小工具。啟用這項權限後,應用程式即會讓其他應用程式使用個人資料 (不建議一般應用程式使用)。"</string>
     <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"修改手機狀態"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"允許應用程式修改應用程式網路使用量的計算方式 (不建議一般應用程式使用)。"</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"存取通知"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"文字動作"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"儲存空間即將用盡"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"部分系統功能可能無法運作"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"確定"</string>
     <string name="cancel" msgid="6442560571259935130">"取消"</string>
     <string name="yes" msgid="5362982303337969312">"確定"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件者:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"手機與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 WiFi 連線"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"平板電腦與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"手機與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 WiFi 連線"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字元"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;&lt;/b&gt;「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在傳送大量簡訊。您要允許這個應用程式繼續傳送簡訊嗎?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"協助工具"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"瀏覽首頁"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"向上瀏覽"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"更多選項"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"內部儲存空間"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD 卡"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
@@ -1465,10 +1482,15 @@
     <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="7382971871993371648">"要將音量調高到安全等級以上嗎?"\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>
     <string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="owner_name" msgid="2716755460376028154">"擁有者"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"錯誤"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"這個應用程式不支援受限的使用者帳戶。"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"找不到支援此操作的應用程式"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 6dc9e68..7f62603 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -200,6 +200,8 @@
     <string name="permgroupdesc_microphone" msgid="7106618286905738408">"Ukufinyelela okuqondile ku-microphone ukuze uqophe umsindo."</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Ikhamela"</string>
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"Ukufinyelela okuqondile kukhamera ekuthwebuleni isithombe noma ividiyo."</string>
+    <string name="permgrouplab_screenlock" msgid="8275500173330718168">"Khiya isikrini"</string>
+    <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"Ikhono lokwazi ukuthinta ukuziphatha kwesikrini sokukhiya kudivayisi yakho."</string>
     <string name="permgrouplab_appInfo" msgid="8028789762634147725">"Ulwazi lezinhlelo zakho zokusebenza"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"Amandla okuthinta ukuziphatha kwezinhlelo zokusebenza kudivayisi yakho."</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"Isithombe sangemuva"</string>
@@ -619,6 +621,10 @@
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Ivumela insiza ukuthi iguqule ukuthii ukusetshenziswa kwenethiwekhi kumiswa kanjani ezinsizeni. Ayisetshenziswa izinsiza ezijwayelekile."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"finyelela kuzaziso"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Ivumela uhlelo lokusebenza ukuthi lithole, lihlole, liphinde lisuse izaziso, ezifaka lezo ezithunyelwe ezinye izinhlelo zokusebenza."</string>
+    <!-- no translation found for permlab_bindNotificationListenerService (7057764742211656654) -->
+    <skip />
+    <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) -->
+    <skip />
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -1046,6 +1052,10 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Izenzo zombhalo"</string>
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Isikhala sokulondoloza siyaphela"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Eminye imisebenzi yohlelo ingahle ingasebenzi"</string>
+    <!-- no translation found for app_running_notification_title (8718335121060787914) -->
+    <skip />
+    <!-- no translation found for app_running_notification_text (4653586947747330058) -->
+    <skip />
     <string name="ok" msgid="5970060430562524910">"KULUNGILE"</string>
     <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
     <string name="yes" msgid="5362982303337969312">"KULUNGILE"</string>
@@ -1139,7 +1149,8 @@
     <string name="wifi_p2p_to_message" msgid="248968974522044099">"Ku:"</string>
     <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Faka i-PIN edingekayo:"</string>
     <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" msgid="7363907213787469151">"Ifoni izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Ithebulethi izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Ifoni izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"I-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ithumela inombolo enkulu yemilayezo ye-SMS. Ufuna ukuvumela lolu hlelo lokusebenza ukuqhubeka ukuthumela imilayezo?"</string>
@@ -1262,6 +1273,8 @@
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Ukufinyeleleka"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Iphephadonga"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
+    <!-- no translation found for notification_listener_binding_label (2014162835481906429) -->
+    <skip />
     <string name="vpn_title" msgid="19615213552042827">"I-VPN isiyasebenza"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
@@ -1365,6 +1378,10 @@
     <string name="action_bar_home_description" msgid="5293600496601490216">"Zulazulela ekhaya"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Zulazulela phezulu"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Izinketho ezingaphezulu"</string>
+    <!-- no translation found for action_bar_home_description_format (7965984360903693903) -->
+    <skip />
+    <!-- no translation found for action_bar_home_subtitle_description_format (6985546530471780727) -->
+    <skip />
     <string name="storage_internal" msgid="4891916833657929263">"Isitoreji sangaphakathi"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"Ikhadi le-SD"</string>
     <string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string>
@@ -1465,10 +1482,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google"\n\n" Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> imizuzwana."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Susa"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Khulisa ivolomu ngaphezu kweleveli yokuphepha?"\n"Ukulalela ngevolomu ephezulu izikhathi ezide kungalimaza ukuzwa kwakho."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"Khulisa ivolomu ngaphezu kwezinga elinconyiwe?"\n"Ukulalela ngevolomu ephezulu izikhathi ezinde kungalimaza ukuzwa kwakho."</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Gcina ucindezele iminwe yakho emibili ukuze unike amandla ukufinyelela."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Ukufinyelela kunikwe amandla."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ukufinyelela kukhanseliwe."</string>
     <string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="owner_name" msgid="2716755460376028154">"Umnikazi"</string>
+    <string name="error_message_title" msgid="4510373083082500195">"Iphutha"</string>
+    <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wabasebenzisi abakhawulelwe"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"Alukho uhlelo lokusebenza olutholakele lokuphatha lesi senzo"</string>
+    <!-- no translation found for revoke (5404479185228271586) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f7ff77b..146607e 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -141,6 +141,10 @@
        <item>@drawable/menu_submenu_background</item>
        <item>@drawable/menu_dropdown_panel_holo_light</item>
        <item>@drawable/menu_dropdown_panel_holo_dark</item>
+       <item>@drawable/menu_popup_panel_holo_light</item>
+       <item>@drawable/menu_popup_panel_holo_dark</item>
+       <item>@drawable/menu_panel_holo_light</item>
+       <item>@drawable/menu_panel_holo_dark</item>
        <item>@drawable/overscroll_edge</item>
        <item>@drawable/overscroll_glow</item>
        <item>@drawable/spinner_16_outer_holo</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4a1d12d..8c7a374 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2092,11 +2092,11 @@
             <!-- Don't use a layer. -->
             <enum name="none" value="0" />
             <!-- Use a software layer. Refer to
-                 {@link android.view.View#setLayerType(int, android.graphics.Paint) for
+                 {@link android.view.View#setLayerType(int, android.graphics.Paint)} for
                  more information. -->
             <enum name="software" value="1" />
             <!-- Use a hardware layer. Refer to
-                 {@link android.view.View#setLayerType(int, android.graphics.Paint) for
+                 {@link android.view.View#setLayerType(int, android.graphics.Paint)} for
                  more information. -->
             <enum name="hardware" value="2" />
         </attr>
@@ -2709,6 +2709,16 @@
              below and above child items.) The height of this will be the same as
              the height of the normal list item divider. -->
         <attr name="childDivider" format="reference|color" />
+        <!-- The start bound for an item's indicator. To specify a start bound specific to children,
+             use childIndicatorStart. -->
+        <attr name="indicatorStart" format="dimension" />
+        <!-- The end bound for an item's indicator. To specify a right bound specific to children,
+             use childIndicatorEnd. -->
+        <attr name="indicatorEnd" format="dimension" />
+        <!-- The start bound for a child's indicator. -->
+        <attr name="childIndicatorStart" format="dimension" />
+        <!-- The end bound for a child's indicator. -->
+        <attr name="childIndicatorEnd" format="dimension" />
     </declare-styleable>
     <declare-styleable name="Gallery">
         <attr name="gravity" />
@@ -3081,12 +3091,12 @@
         <!-- Specifies the formatting pattern used to show the time and/or date
              in 12-hour mode. Please refer to {@link android.text.format.DateFormat}
              for a complete description of accepted formatting patterns.
-             The default pattern is "h:mm aa". -->
+             The default pattern is a locale-appropriate equivalent of "h:mm a". -->
         <attr name="format12Hour" format="string"/>
         <!-- Specifies the formatting pattern used to show the time and/or date
              in 24-hour mode. Please refer to {@link android.text.format.DateFormat}
              for a complete description of accepted formatting patterns.
-             The default pattern is "k:mm". -->
+             The default pattern is a locale-appropriate equivalent of "H:mm". -->
         <attr name="format24Hour" format="string"/>
         <!-- Specifies the time zone to use. When this attribute is specified, the
              TextClock will ignore the time zone of the system. To use the user's
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d899e9d..0afe4c1 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -254,7 +254,11 @@
          not normally be used by applications; it requires that the system keep
          your application running at all times. -->
     <attr name="persistent" format="boolean" />
-    
+
+    <!-- Flag to specify if this application needs to be present for all users. Only pre-installed
+         applications can request this feature. Default value is false. -->
+    <attr name="requiredForAllUsers" format="boolean" />
+
     <!-- Flag indicating whether the application can be debugged, even when
          running on a device that is running in user mode. -->
     <attr name="debuggable" format="boolean" />
@@ -844,6 +848,7 @@
              for normal behavior. -->
         <attr name="hasCode" format="boolean" />
         <attr name="persistent" />
+        <attr name="requiredForAllUsers" />
         <!-- Specify whether the components in this application are enabled or not (that is, can be
              instantiated by the system).
              If "false", it overrides any component specific values (a value of "true" will not
@@ -884,6 +889,11 @@
         <!-- Declare that your application will be able to deal with RTL (right to left) layouts.
              If set to  false (default value), your application will not care about RTL layouts. -->
         <attr name="supportsRtl" format="boolean" />
+        <!-- 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" -->
+        <attr name="restrictedAccountType" format="string"/>
     </declare-styleable>
     
     <!-- The <code>permission</code> tag declares a security permission that can be
@@ -986,9 +996,8 @@
               permission, and it must always be granted when it is installed.
               If you set this to false, then in some cases the application may
               be installed with it being granted the permission, and it will
-              need to request the permission later if it needs it.
+              need to request the permission later if it needs it. -->
         <attr name="required" format="boolean" />
-        -->
     </declare-styleable>
 
     <!-- The <code>uses-configuration</code> tag specifies
@@ -1031,7 +1040,7 @@
               don't support it.  If you set this to false, then this will
               not impose a restriction on where the application can be
               installed. -->
-        <attr name="required" format="boolean" />
+        <attr name="required" />
     </declare-styleable>
 
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
@@ -1065,6 +1074,21 @@
         <attr name="maxSdkVersion" format="integer" />
     </declare-styleable>
     
+    <!-- The <code>library</code> tag declares that this apk is providing itself
+         as a shared library for other applications to use.  It can only be used
+         with apks that are built in to the system image.  Other apks can link to
+         it with the {@link #AndroidManifestUsesLibrary uses-library} tag.
+
+         <p>This appears as a child tag of the
+         {@link #AndroidManifestApplication application} tag. -->
+    <declare-styleable name="AndroidManifestLibrary" parent="AndroidManifest">
+        <!-- Required public name of the library, which other components and
+        packages will use when referring to this library.  This is a string using
+        Java-style scoping to ensure it is unique.  The name should typically
+        be the same as the apk's package name. -->
+        <attr name="name" />
+    </declare-styleable>
+
     <!-- The <code>uses-libraries</code> specifies a shared library that this
          package requires to be linked against.  Specifying this flag tells the
          system to include this library's code in your class loader.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ccdddd8..cc50d8a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1031,4 +1031,21 @@
 
     <!-- Flag indicating if the speed up audio on mt call code should be executed -->
     <bool name="config_speed_up_audio_on_mt_calls">false</bool>
+
+    <!-- Class name of the framework account picker activity.
+         Can be customized for other product types -->
+    <string name="config_chooseAccountActivity"
+            >android/android.accounts.ChooseAccountActivity</string>
+    <!-- Class name of the account type and account picker activity.
+         Can be customized for other product types -->
+    <string name="config_chooseTypeAndAccountActivity"
+            >android/android.accounts.ChooseTypeAndAccountActivity</string>
+
+    <!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
+    <string name="config_appsAuthorizedForSharedAccounts"></string>
+
+    <!-- Flag indicating that the media framework should not allow changes or mute on any
+         stream or master volumes. -->
+    <bool name="config_useFixedVolume">false</bool>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 42e5cf1..42d692f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2033,15 +2033,16 @@
      =============================================================== -->
   <eat-comment />
 
-  <public type="attr" name="mipMap" id="0x010103cd" />
-  <public type="attr" name="mirrorForRtl" id="0x010103ce" />
-
-    <!-- ===============================================================
-         Resources added in version 19 of the platform
-         =============================================================== -->
-      <eat-comment />
-
+  <public type="attr" name="mipMap" />
+  <public type="attr" name="mirrorForRtl" />
   <public type="attr" name="windowOverscan" />
+  <public type="attr" name="requiredForAllUsers" />
+  <public type="attr" name="indicatorStart"  />
+  <public type="attr" name="indicatorEnd" />
+  <public type="attr" name="childIndicatorStart" />
+  <public type="attr" name="childIndicatorEnd" />
+  <public type="attr" name="restrictedAccountType" />
+
   <public type="style" name="Theme.NoTitleBar.Overscan" />
   <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
   <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 447d94c..a0e1603 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -474,6 +474,11 @@
     <string name="permgroupdesc_camera">Direct access to camera for image or video capture.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permgrouplab_screenlock">Lock screen</string>
+    <!-- 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_screenlock">Ability to affect behavior of the lock screen on your device.</string>
+
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_appInfo">Your applications information</string>
     <!-- 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_appInfo">Ability to affect behavior of other applications on your device.</string>
@@ -1811,6 +1816,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessNotifications">Allows the app to retrieve, examine, and clear notifications, including those posted by other 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_bindNotificationListenerService">bind to a notification listener 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_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
@@ -2984,6 +2994,15 @@
     <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the message of that notification. -->
     <string name="low_internal_storage_view_text">Some system functions may not work</string>
 
+    <!-- [CHAR LIMIT=NONE] Stub notification title for an app running a service that has provided
+         a bad bad notification for itself. -->
+    <string name="app_running_notification_title"><xliff:g id="app_name">%1$s</xliff:g>
+        is running</string>
+    <!-- [CHAR LIMIT=NONE] Stub notification text for an app running a service that has provided
+         a bad bad notification for itself. -->
+    <string name="app_running_notification_text">Touch for more information
+        or to stop the app.</string>
+
     <!-- Preference framework strings. -->
     <string name="ok">OK</string>
     <!-- Preference framework strings. -->
@@ -3188,7 +3207,8 @@
     <string name="wifi_p2p_enter_pin_message">Type the required PIN: </string>
     <string name="wifi_p2p_show_pin_message">PIN: </string>
 
-    <string name="wifi_p2p_frequency_conflict_message">The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
+    <string name="wifi_p2p_frequency_conflict_message" product="tablet">The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
+    <string name="wifi_p2p_frequency_conflict_message" product="default">The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="device_name">%1$s</xliff:g></string>
 
     <!-- Name of the dialog that lets the user choose an accented character to insert -->
     <string name="select_character">Insert character</string>
@@ -3493,6 +3513,9 @@
     <string name="wallpaper_binding_label">Wallpaper</string>
     <!-- Dialog title for user to select a different wallpaper from service list -->
     <string name="chooser_wallpaper">Change wallpaper</string>
+    <!-- Label to show for a service that is running because it is observing
+         the user's notifications. -->
+    <string name="notification_listener_binding_label">Notification listener</string>
 
     <!-- Do Not Translate: Alternate eri.xml -->
     <string name="alternate_eri_file">/data/eri.xml</string>
@@ -3748,6 +3771,17 @@
     <string name="action_bar_up_description">Navigate up</string>
     <!-- Content description for the action menu overflow button. [CHAR LIMIT=NONE] -->
     <string name="action_menu_overflow_description">More options</string>
+    <!-- Formatting string for describing the action bar's title/home/up affordance.
+         This is a single tappable "button" that includes the app icon, the Up indicator
+         (usually a "<" chevron) and the window title text.
+         %1$s is the title. %2$s is the description of what tapping/clicking the whole
+         thing is going to do. -->
+    <string name="action_bar_home_description_format">%1$s, %2$s</string>
+    <!-- Just like action_bar_home_description_format, but this one will be used
+         if the window is also providing subtitle text.
+         %1$s is the title. %2$s is the subtitle. %3$s is the description of what
+         tapping/clicking the whole thing is going to do. -->
+    <string name="action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>
 
     <!-- Storage description for internal storage. [CHAR LIMIT=NONE] -->
     <string name="storage_internal">Internal storage</string>
@@ -4035,7 +4069,7 @@
     <!-- Message shown in dialog when user is attempting to set the music volume above the
     recommended maximum level for headphones -->
     <string name="safe_media_volume_warning" product="default">
-       "Raise volume above safe level?\nListening at high volume for long periods may damage your hearing."
+       "Raise volume above recommended level?\nListening at high volume for long periods may damage your hearing."
     </string>
 
     <!-- Text spoken when the user is performing a gesture that will enable accessibility. [CHAR LIMIT=none] -->
@@ -4048,5 +4082,11 @@
     <string name="user_switched">Current user <xliff:g id="name" example="Bob">%1$s</xliff:g>.</string>
     <!-- Default name of the owner user [CHAR LIMIT=20] -->
     <string name="owner_name" msgid="3879126011135546571">Owner</string>
-
+    <!-- Error message title [CHAR LIMIT=35] -->
+    <string name="error_message_title">Error</string>
+    <!-- Message informing user that app is not permitted to access accounts. [CHAR LIMIT=none] -->
+    <string name="app_no_restricted_accounts">This application does not support accounts for limited users</string>
+    <!-- Message informing user that the requested activity could not be found [CHAR LIMIT=none] -->
+    <string name="app_not_found">No application found to handle this action</string>
+    <string name="revoke">Revoke</string>
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 56c2235..f494d8c 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1869,7 +1869,7 @@
 
     <style name="Widget.Holo.ListPopupWindow" parent="Widget.ListPopupWindow">
         <item name="android:dropDownSelector">@android:drawable/list_selector_holo_dark</item>
-        <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
+        <item name="android:popupBackground">@android:drawable/menu_panel_holo_dark</item>
         <item name="android:dropDownVerticalOffset">0dip</item>
         <item name="android:dropDownHorizontalOffset">0dip</item>
         <item name="android:dropDownWidth">wrap_content</item>
@@ -2242,7 +2242,7 @@
 
     <style name="Widget.Holo.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
         <item name="android:dropDownSelector">@android:drawable/list_selector_holo_light</item>
-        <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_light</item>
+        <item name="android:popupBackground">@android:drawable/menu_panel_holo_light</item>
         <item name="android:dropDownVerticalOffset">0dip</item>
         <item name="android:dropDownHorizontalOffset">0dip</item>
         <item name="android:dropDownWidth">wrap_content</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 140ff70..e06bcd1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -277,6 +277,7 @@
   <java-symbol type="bool" name="config_camera_sound_forced" />
   <java-symbol type="bool" name="config_dontPreferApn" />
   <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
+  <java-symbol type="bool" name="config_useFixedVolume" />
 
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
@@ -330,6 +331,8 @@
   <java-symbol type="string" name="addToDictionary" />
   <java-symbol type="string" name="action_bar_home_description" />
   <java-symbol type="string" name="action_bar_up_description" />
+  <java-symbol type="string" name="app_running_notification_title" />
+  <java-symbol type="string" name="app_running_notification_text" />
   <java-symbol type="string" name="delete" />
   <java-symbol type="string" name="deleteText" />
   <java-symbol type="string" name="ellipsis_two_dots" />
@@ -707,6 +710,7 @@
   <java-symbol type="string" name="relationTypeSpouse" />
   <java-symbol type="string" name="relative_time" />
   <java-symbol type="string" name="reset" />
+  <java-symbol type="string" name="revoke" />
   <java-symbol type="string" name="ringtone_default" />
   <java-symbol type="string" name="ringtone_default_with_actual" />
   <java-symbol type="string" name="ringtone_picker_title" />
@@ -863,6 +867,12 @@
   <java-symbol type="string" name="media_route_status_available" />
   <java-symbol type="string" name="media_route_status_not_available" />
   <java-symbol type="string" name="owner_name" />
+  <java-symbol type="string" name="config_chooseAccountActivity" />
+  <java-symbol type="string" name="config_chooseTypeAndAccountActivity" />
+  <java-symbol type="string" name="config_appsAuthorizedForSharedAccounts" />
+  <java-symbol type="string" name="error_message_title" />
+  <java-symbol type="string" name="action_bar_home_description_format" />
+  <java-symbol type="string" name="action_bar_home_subtitle_description_format" />
 
   <java-symbol type="plurals" name="abbrev_in_num_days" />
   <java-symbol type="plurals" name="abbrev_in_num_hours" />
@@ -1114,6 +1124,7 @@
   <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
   <java-symbol type="layout" name="keyguard_add_widget" />
   <java-symbol type="layout" name="action_bar_up_container" />
+  <java-symbol type="layout" name="app_not_authorized" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
@@ -1133,6 +1144,8 @@
   <java-symbol type="xml" name="power_profile" />
   <java-symbol type="xml" name="time_zones_by_country" />
   <java-symbol type="xml" name="sms_short_codes" />
+  <java-symbol type="xml" name="audio_assets" />
+  <java-symbol type="xml" name="global_keys" />
 
   <java-symbol type="raw" name="accessibility_gestures" />
   <java-symbol type="raw" name="incognito_mode_start_page" />
@@ -1319,6 +1332,7 @@
   <java-symbol type="id" name="keyguard_bouncer_frame" />
   <java-symbol type="id" name="app_widget_container" />
   <java-symbol type="id" name="view_flipper" />
+  <java-symbol type="id" name="carrier_text" />
   <java-symbol type="id" name="emergency_call_button" />
   <java-symbol type="id" name="keyguard_host_view" />
   <java-symbol type="id" name="delete_button" />
@@ -1627,6 +1641,7 @@
   <java-symbol type="string" name="launch_warning_title" />
   <java-symbol type="string" name="low_internal_storage_view_text" />
   <java-symbol type="string" name="low_internal_storage_view_title" />
+  <java-symbol type="string" name="notification_listener_binding_label" />
   <java-symbol type="string" name="report" />
   <java-symbol type="string" name="select_input_method" />
   <java-symbol type="string" name="select_keyboard_layout_notification_title" />
diff --git a/core/res/res/xml/apns.xml b/core/res/res/xml/apns.xml
index 8c7245c..249b598 100644
--- a/core/res/res/xml/apns.xml
+++ b/core/res/res/xml/apns.xml
@@ -20,6 +20,6 @@
 
 <!-- If you edit this version, also edit the version in the partner-supplied
     apns-conf.xml configuration file -->
-<apns version="7">
+<apns version="8">
 
 </apns>
diff --git a/core/res/res/xml/audio_assets.xml b/core/res/res/xml/audio_assets.xml
new file mode 100644
index 0000000..746dbab
--- /dev/null
+++ b/core/res/res/xml/audio_assets.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- Mapping of UI sound effects to audio assets under /system/media/audio/ui.
+     Modify this file to override default sound assets.
+     Currently only touch sounds can be overridden. Other groups can be added
+     in the future for other UI sounds like camera, lock, dock...
+-->
+
+<audio_assets version="1.0">
+    <group name="touch_sounds">
+        <asset id="FX_KEY_CLICK" file="Effect_Tick.ogg"/>
+        <asset id="FX_FOCUS_NAVIGATION_UP" file="Effect_Tick.ogg"/>
+        <asset id="FX_FOCUS_NAVIGATION_DOWN" file="Effect_Tick.ogg"/>
+        <asset id="FX_FOCUS_NAVIGATION_LEFT" file="Effect_Tick.ogg"/>
+        <asset id="FX_FOCUS_NAVIGATION_RIGHT" file="Effect_Tick.ogg"/>
+        <asset id="FX_KEYPRESS_STANDARD" file="KeypressStandard.ogg"/>
+        <asset id="FX_KEYPRESS_SPACEBAR" file="KeypressSpacebar.ogg"/>
+        <asset id="FX_KEYPRESS_DELETE" file="KeypressDelete.ogg"/>
+        <asset id="FX_KEYPRESS_RETURN" file="KeypressReturn.ogg"/>
+    </group>
+</audio_assets>
diff --git a/core/res/res/xml/global_keys.xml b/core/res/res/xml/global_keys.xml
new file mode 100644
index 0000000..8fa6902
--- /dev/null
+++ b/core/res/res/xml/global_keys.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- Mapping of keycodes to components which will be handled globally.
+     Modify this file to add global keys.
+     A global key will NOT go to the foreground application and instead only ever be sent via targeted
+     broadcast to the specified component. The action of the intent will be
+     android.intent.action.GLOBAL_BUTTON and the KeyEvent will be included in the intent as
+     android.intent.extra.KEY_EVENT.
+-->
+
+<global_keys version="1">
+    <!-- Example format: keyCode = keycode to handle globally. component = component which will handle this key. -->
+    <!-- <key keyCode="KEYCODE_VOLUME_UP" component="com.android.example.keys/.VolumeKeyHandler" /> -->
+</global_keys>
diff --git a/core/res/res/xml/kg_password_kbd_numeric.xml b/core/res/res/xml/kg_password_kbd_numeric.xml
old mode 100755
new mode 100644
diff --git a/core/tests/benchmarks/src/com/android/internal/util/IndentingPrintWriterBenchmark.java b/core/tests/benchmarks/src/com/android/internal/util/IndentingPrintWriterBenchmark.java
new file mode 100644
index 0000000..34c73e8
--- /dev/null
+++ b/core/tests/benchmarks/src/com/android/internal/util/IndentingPrintWriterBenchmark.java
@@ -0,0 +1,152 @@
+/*
+ * 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.internal.util;
+
+import com.google.android.collect.Lists;
+import com.google.caliper.SimpleBenchmark;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+public class IndentingPrintWriterBenchmark extends SimpleBenchmark {
+
+    private PrintWriter mDirect;
+    private IndentingPrintWriter mIndenting;
+
+    private Node mSimple;
+    private Node mComplex;
+
+    @Override
+    protected void setUp() throws IOException {
+        final FileOutputStream os = new FileOutputStream(new File("/dev/null"));
+        mDirect = new PrintWriter(os);
+        mIndenting = new IndentingPrintWriter(mDirect, "  ");
+
+        final Node manyChildren = Node.build("ManyChildren", Node.build("1"), Node.build("2"),
+                Node.build("3"), Node.build("4"), Node.build("5"), Node.build("6"), Node.build("7"),
+                Node.build("8"), Node.build("9"), Node.build("10"));
+
+        mSimple = Node.build("RED");
+        mComplex = Node.build("PARENT", Node.build("RED"), Node.build("GREEN",
+                Node.build("BLUE", manyChildren, manyChildren), manyChildren, manyChildren),
+                manyChildren);
+    }
+
+    @Override
+    protected void tearDown() {
+        mIndenting.close();
+        mIndenting = null;
+        mDirect = null;
+    }
+
+    public void timeSimpleDirect(int reps) {
+        for (int i = 0; i < reps; i++) {
+            mSimple.dumpDirect(mDirect, 0);
+        }
+    }
+
+    public void timeSimpleIndenting(int reps) {
+        for (int i = 0; i < reps; i++) {
+            mSimple.dumpIndenting(mIndenting);
+        }
+    }
+
+    public void timeComplexDirect(int reps) {
+        for (int i = 0; i < reps; i++) {
+            mComplex.dumpDirect(mDirect, 0);
+        }
+    }
+
+    public void timeComplexIndenting(int reps) {
+        for (int i = 0; i < reps; i++) {
+            mComplex.dumpIndenting(mIndenting);
+        }
+    }
+
+    public void timePairRaw(int reps) {
+        final int value = 1024;
+        for (int i = 0; i < reps; i++) {
+            mDirect.print("key=");
+            mDirect.print(value);
+            mDirect.print(" ");
+        }
+    }
+
+    public void timePairIndenting(int reps) {
+        final int value = 1024;
+        for (int i = 0; i < reps; i++) {
+            mIndenting.printPair("key", value);
+        }
+    }
+
+    private static class Node {
+        public String name;
+        public ArrayList<Node> children;
+
+        private static String[] sIndents = new String[] { "", "  ", "    ", "      ", "        " };
+
+        public static Node build(String name, Node... children) {
+            Node node = new Node();
+            node.name = name;
+            if (children != null && children.length > 0) {
+                node.children = Lists.newArrayList(children);
+            }
+            return node;
+        }
+
+        private void dumpSelf(PrintWriter pw) {
+            pw.print("Node ");
+            pw.print(name);
+            pw.print(" first ");
+            pw.print(512);
+            pw.print(" second ");
+            pw.print(1024);
+            pw.print(" third ");
+            pw.println(2048);
+        }
+
+        public void dumpDirect(PrintWriter pw, int depth) {
+            pw.print(sIndents[depth]);
+            dumpSelf(pw);
+
+            if (children != null) {
+                for (Node child : children) {
+                    child.dumpDirect(pw, depth + 1);
+                }
+            }
+
+            pw.println();
+        }
+
+        public void dumpIndenting(IndentingPrintWriter pw) {
+            dumpSelf(pw);
+
+            if (children != null) {
+                pw.increaseIndent();
+                for (Node child : children) {
+                    child.dumpIndenting(pw);
+                }
+                pw.decreaseIndent();
+            }
+
+            pw.println();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
new file mode 100644
index 0000000..b1f88db
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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;
+
+import android.os.Handler;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+public class AutoCancelTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+    boolean mAnimX1Canceled = false;
+    boolean mAnimXY1Canceled = false;
+    boolean mAnimX2Canceled = false;
+    boolean mAnimXY2Canceled = false;
+
+    private static final long START_DELAY = 100;
+    private static final long DELAYED_START_DURATION = 200;
+    private static final long FUTURE_TIMEOUT = 1000;
+
+    HashMap<Animator, Boolean> mCanceledMap = new HashMap<Animator, Boolean>();
+
+    public AutoCancelTest() {
+        super(BasicAnimatorActivity.class);
+    }
+
+    ObjectAnimator setupAnimator(long startDelay, String... properties) {
+        ObjectAnimator returnVal;
+        if (properties.length == 1) {
+            returnVal = ObjectAnimator.ofFloat(this, properties[0], 0, 1);
+        } else {
+            PropertyValuesHolder[] pvhArray = new PropertyValuesHolder[properties.length];
+            for (int i = 0; i < properties.length; i++) {
+                pvhArray[i] = PropertyValuesHolder.ofFloat(properties[i], 0, 1);
+            }
+            returnVal = ObjectAnimator.ofPropertyValuesHolder(this, pvhArray);
+        }
+        returnVal.setAutoCancel(true);
+        returnVal.setStartDelay(startDelay);
+        returnVal.addListener(mCanceledListener);
+        return returnVal;
+    }
+
+    private void setupAnimators(long startDelay, boolean startLater, final FutureWaiter future)
+    throws Exception {
+        // Animators to be auto-canceled
+        final ObjectAnimator animX1 = setupAnimator(startDelay, "x");
+        final ObjectAnimator animY1 = setupAnimator(startDelay, "y");
+        final ObjectAnimator animXY1 = setupAnimator(startDelay, "x", "y");
+        final ObjectAnimator animXZ1 = setupAnimator(startDelay, "x", "z");
+
+        animX1.start();
+        animY1.start();
+        animXY1.start();
+        animXZ1.start();
+
+        final ObjectAnimator animX2 = setupAnimator(0, "x");
+        animX2.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                // We expect only animX1 to be canceled at this point
+                if (mCanceledMap.get(animX1) == null ||
+                        mCanceledMap.get(animX1) != true ||
+                        mCanceledMap.get(animY1) != null ||
+                        mCanceledMap.get(animXY1) != null ||
+                        mCanceledMap.get(animXZ1) != null) {
+                    future.set(false);
+                }
+            }
+        });
+
+        final ObjectAnimator animXY2 = setupAnimator(0, "x", "y");
+        animXY2.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                // We expect only animXY1 to be canceled at this point
+                if (mCanceledMap.get(animXY1) == null ||
+                        mCanceledMap.get(animXY1) != true ||
+                        mCanceledMap.get(animY1) != null ||
+                        mCanceledMap.get(animXZ1) != null) {
+                    future.set(false);
+                }
+
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Release future if not done already via failures during start
+                future.release();
+            }
+        });
+
+        if (startLater) {
+            Handler handler = new Handler();
+            handler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    animX2.start();
+                    animXY2.start();
+                }
+            }, DELAYED_START_DURATION);
+        } else {
+            animX2.start();
+            animXY2.start();
+        }
+    }
+
+    @SmallTest
+    public void testAutoCancel() throws Exception {
+        final FutureWaiter future = new FutureWaiter();
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setupAnimators(0, false, future);
+                } catch (Exception e) {
+                    future.setException(e);
+                }
+            }
+        });
+        assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @SmallTest
+    public void testAutoCancelDelayed() throws Exception {
+        final FutureWaiter future = new FutureWaiter();
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setupAnimators(START_DELAY, false, future);
+                } catch (Exception e) {
+                    future.setException(e);
+                }
+            }
+        });
+        assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @SmallTest
+    public void testAutoCancelTestLater() throws Exception {
+        final FutureWaiter future = new FutureWaiter();
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setupAnimators(0, true, future);
+                } catch (Exception e) {
+                    future.setException(e);
+                }
+            }
+        });
+        assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @SmallTest
+    public void testAutoCancelDelayedTestLater() throws Exception {
+        final FutureWaiter future = new FutureWaiter();
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setupAnimators(START_DELAY, true, future);
+                } catch (Exception e) {
+                    future.setException(e);
+                }
+            }
+        });
+        assertTrue(future.get(FUTURE_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    private AnimatorListenerAdapter mCanceledListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceledMap.put(animation, true);
+        }
+    };
+
+    public void setX(float x) {}
+
+    public void setY(float y) {}
+
+    public void setZ(float z) {}
+}
+
+
diff --git a/core/tests/coretests/src/android/animation/FutureWaiter.java b/core/tests/coretests/src/android/animation/FutureWaiter.java
index 320a1c2..0c65e20 100644
--- a/core/tests/coretests/src/android/animation/FutureWaiter.java
+++ b/core/tests/coretests/src/android/animation/FutureWaiter.java
@@ -23,14 +23,21 @@
  * {@link com.google.common.util.concurrent.AbstractFuture#set(Object)} method internally. It
  * also exposes the protected {@link AbstractFuture#setException(Throwable)} method.
  */
-public class FutureWaiter extends AbstractFuture<Void> {
+public class FutureWaiter extends AbstractFuture<Boolean> {
 
     /**
      * Release the Future currently waiting on
      * {@link com.google.common.util.concurrent.AbstractFuture#get()}.
      */
     public void release() {
-        super.set(null);
+        super.set(true);
+    }
+
+    /**
+     * Used to indicate failure (when the result value is false).
+     */
+    public void set(boolean result) {
+        super.set(result);
     }
 
     @Override
diff --git a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
index cc8c4a6..37495e1 100644
--- a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
+++ b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
@@ -18,64 +18,51 @@
 
 import android.os.Parcel;
 import android.test.AndroidTestCase;
-import android.util.Base64;
 
-import java.util.jar.Attributes;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
 
 public class ManifestDigestTest extends AndroidTestCase {
-    private static final byte[] DIGEST_1 = {
+    private static final byte[] MESSAGE_1 = {
             (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
     };
 
-    private static final String DIGEST_1_STR = Base64.encodeToString(DIGEST_1, Base64.DEFAULT);
-
-    private static final byte[] DIGEST_2 = {
-            (byte) 0x0A, (byte) 0xA5, (byte) 0xF0, (byte) 0x5A
-    };
-
-    private static final String DIGEST_2_STR = Base64.encodeToString(DIGEST_2, Base64.DEFAULT);
-
-    private static final Attributes.Name SHA1_DIGEST = new Attributes.Name("SHA1-Digest");
-
-    private static final Attributes.Name MD5_DIGEST = new Attributes.Name("MD5-Digest");
-
-    public void testManifestDigest_FromAttributes_Null() {
+    public void testManifestDigest_FromInputStream_Null() {
         assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
-                ManifestDigest.fromAttributes(null));
+                ManifestDigest.fromInputStream(null));
     }
 
-    public void testManifestDigest_FromAttributes_NoAttributes() {
-        Attributes a = new Attributes();
+    public void testManifestDigest_FromInputStream_ThrowsIoException() {
+        InputStream is = new InputStream() {
+            @Override
+            public int read() throws IOException {
+                throw new IOException();
+            }
+        };
 
-        assertNull("There were no attributes to extract, so ManifestDigest should be null",
-                ManifestDigest.fromAttributes(a));
+        assertNull("InputStream threw exception, so ManifestDigest should be null",
+                ManifestDigest.fromInputStream(is));
     }
 
-    public void testManifestDigest_FromAttributes_SHA1PreferredOverMD5() {
-        Attributes a = new Attributes();
-        a.put(SHA1_DIGEST, DIGEST_1_STR);
+    public void testManifestDigest_Equals() throws Exception {
+        InputStream is = new ByteArrayInputStream(MESSAGE_1);
 
-        a.put(MD5_DIGEST, DIGEST_2_STR);
+        ManifestDigest expected =
+                new ManifestDigest(MessageDigest.getInstance("SHA-256").digest(MESSAGE_1));
 
-        ManifestDigest fromAttributes = ManifestDigest.fromAttributes(a);
+        ManifestDigest actual = ManifestDigest.fromInputStream(is);
+        assertEquals(expected, actual);
 
-        assertNotNull("A valid ManifestDigest should be returned", fromAttributes);
-
-        ManifestDigest created = new ManifestDigest(DIGEST_1);
-
-        assertEquals("SHA-1 should be preferred over MD5: " + created.toString() + " vs. "
-                + fromAttributes.toString(), created, fromAttributes);
-
-        assertEquals("Hash codes should be the same: " + created.toString() + " vs. "
-                + fromAttributes.toString(), created.hashCode(), fromAttributes
-                .hashCode());
+        ManifestDigest unexpected = new ManifestDigest(new byte[0]);
+        assertFalse(unexpected.equals(actual));
     }
 
-    public void testManifestDigest_Parcel() {
-        Attributes a = new Attributes();
-        a.put(SHA1_DIGEST, DIGEST_1_STR);
+    public void testManifestDigest_Parcel() throws Exception {
+        InputStream is = new ByteArrayInputStream(MESSAGE_1);
 
-        ManifestDigest digest = ManifestDigest.fromAttributes(a);
+        ManifestDigest digest = ManifestDigest.fromInputStream(is);
 
         Parcel p = Parcel.obtain();
         digest.writeToParcel(p, 0);
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index e3b6b5f..d6a7ee2 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -22,6 +22,7 @@
 import junit.framework.TestCase;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 
 public class LinkPropertiesTest extends TestCase {
     private static String ADDRV4 = "75.208.6.1";
@@ -32,14 +33,41 @@
     private static String GATEWAY2 = "69.78.8.1";
     private static String NAME = "qmi0";
 
+    public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
+        // Check implementation of equals(), element by element.
+        assertTrue(source.isIdenticalInterfaceName(target));
+        assertTrue(target.isIdenticalInterfaceName(source));
+
+        assertTrue(source.isIdenticalAddresses(target));
+        assertTrue(target.isIdenticalAddresses(source));
+
+        assertTrue(source.isIdenticalDnses(target));
+        assertTrue(target.isIdenticalDnses(source));
+
+        assertTrue(source.isIdenticalRoutes(target));
+        assertTrue(target.isIdenticalRoutes(source));
+
+        assertTrue(source.isIdenticalHttpProxy(target));
+        assertTrue(target.isIdenticalHttpProxy(source));
+
+        assertTrue(source.isIdenticalStackedLinks(target));
+        assertTrue(target.isIdenticalStackedLinks(source));
+
+        // Check result of equals().
+        assertTrue(source.equals(target));
+        assertTrue(target.equals(source));
+
+        // Check hashCode.
+        assertEquals(source.hashCode(), target.hashCode());
+    }
+
     @SmallTest
     public void testEqualsNull() {
         LinkProperties source = new LinkProperties();
         LinkProperties target = new LinkProperties();
 
         assertFalse(source == target);
-        assertTrue(source.equals(target));
-        assertTrue(source.hashCode() == target.hashCode());
+        assertLinkPropertiesEqual(source, target);
     }
 
     @SmallTest
@@ -72,8 +100,7 @@
             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
 
-            assertTrue(source.equals(target));
-            assertTrue(source.hashCode() == target.hashCode());
+            assertLinkPropertiesEqual(source, target);
 
             target.clear();
             // change Interface Name
@@ -162,8 +189,7 @@
             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
 
-            assertTrue(source.equals(target));
-            assertTrue(source.hashCode() == target.hashCode());
+            assertLinkPropertiesEqual(source, target);
         } catch (Exception e) {
             fail();
         }
@@ -190,11 +216,95 @@
             target.addLinkAddress(new LinkAddress(
                     NetworkUtils.numericToInetAddress(ADDRV6), 128));
 
-            assertTrue(source.equals(target));
-            assertTrue(source.hashCode() == target.hashCode());
+            assertLinkPropertiesEqual(source, target);
         } catch (Exception e) {
             fail();
         }
     }
 
+    private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
+        for (RouteInfo r : lp.getRoutes()) {
+            assertEquals(iface, r.getInterface());
+        }
+    }
+
+    @SmallTest
+    public void testRouteInterfaces() {
+        LinkAddress prefix = new LinkAddress(
+            NetworkUtils.numericToInetAddress("2001:db8::"), 32);
+        InetAddress address = NetworkUtils.numericToInetAddress(ADDRV6);
+
+        // Add a route with no interface to a LinkProperties with no interface. No errors.
+        LinkProperties lp = new LinkProperties();
+        RouteInfo r = new RouteInfo(prefix, address, null);
+        lp.addRoute(r);
+        assertEquals(1, lp.getRoutes().size());
+        assertAllRoutesHaveInterface(null, lp);
+
+        // Add a route with an interface. Except an exception.
+        r = new RouteInfo(prefix, address, "wlan0");
+        try {
+          lp.addRoute(r);
+          fail("Adding wlan0 route to LP with no interface, expect exception");
+        } catch (IllegalArgumentException expected) {}
+
+        // Change the interface name. All the routes should change their interface name too.
+        lp.setInterfaceName("rmnet0");
+        assertAllRoutesHaveInterface("rmnet0", lp);
+
+        // Now add a route with the wrong interface. This causes an exception too.
+        try {
+          lp.addRoute(r);
+          fail("Adding wlan0 route to rmnet0 LP, expect exception");
+        } catch (IllegalArgumentException expected) {}
+
+        // If the interface name matches, the route is added.
+        lp.setInterfaceName("wlan0");
+        lp.addRoute(r);
+        assertEquals(2, lp.getRoutes().size());
+        assertAllRoutesHaveInterface("wlan0", lp);
+
+        // Routes with null interfaces are converted to wlan0.
+        r = RouteInfo.makeHostRoute(NetworkUtils.numericToInetAddress(ADDRV6), null);
+        lp.addRoute(r);
+        assertEquals(3, lp.getRoutes().size());
+        assertAllRoutesHaveInterface("wlan0", lp);
+
+        // Check comparisons work.
+        LinkProperties lp2 = new LinkProperties(lp);
+        assertAllRoutesHaveInterface("wlan0", lp);
+        assertEquals(0, lp.compareRoutes(lp2).added.size());
+        assertEquals(0, lp.compareRoutes(lp2).removed.size());
+
+        lp2.setInterfaceName("p2p0");
+        assertAllRoutesHaveInterface("p2p0", lp2);
+        assertEquals(3, lp.compareRoutes(lp2).added.size());
+        assertEquals(3, lp.compareRoutes(lp2).removed.size());
+    }
+
+    @SmallTest
+    public void testStackedInterfaces() {
+        LinkProperties rmnet0 = new LinkProperties();
+        rmnet0.setInterfaceName("rmnet0");
+
+        LinkProperties clat4 = new LinkProperties();
+        clat4.setInterfaceName("clat4");
+
+        assertEquals(0, rmnet0.getStackedLinks().size());
+        rmnet0.addStackedLink(clat4);
+        assertEquals(1, rmnet0.getStackedLinks().size());
+        rmnet0.addStackedLink(clat4);
+        assertEquals(1, rmnet0.getStackedLinks().size());
+        assertEquals(0, clat4.getStackedLinks().size());
+
+        // Modify an item in the returned collection to see what happens.
+        for (LinkProperties link : rmnet0.getStackedLinks()) {
+            if (link.getInterfaceName().equals("clat4")) {
+               link.setInterfaceName("newname");
+            }
+        }
+        for (LinkProperties link : rmnet0.getStackedLinks()) {
+            assertFalse("newname".equals(link.getInterfaceName()));
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
new file mode 100644
index 0000000..55d6592
--- /dev/null
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import android.os.Parcel;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class RouteInfoTest extends TestCase {
+
+    private InetAddress Address(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+
+    private LinkAddress Prefix(String prefix) {
+        String[] parts = prefix.split("/");
+        return new LinkAddress(Address(parts[0]), Integer.parseInt(parts[1]));
+    }
+
+    @SmallTest
+    public void testConstructor() {
+        RouteInfo r;
+
+        // Invalid input.
+        try {
+            r = new RouteInfo(null, null, "rmnet0");
+            fail("Expected RuntimeException:  destination and gateway null");
+        } catch(RuntimeException e) {}
+
+        // Null destination is default route.
+        r = new RouteInfo(null, Address("2001:db8::1"), null);
+        assertEquals(Prefix("::/0"), r.getDestination());
+        assertEquals(Address("2001:db8::1"), r.getGateway());
+        assertNull(r.getInterface());
+
+        r = new RouteInfo(null, Address("192.0.2.1"), "wlan0");
+        assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
+        assertEquals(Address("192.0.2.1"), r.getGateway());
+        assertEquals("wlan0", r.getInterface());
+
+        // Null gateway sets gateway to unspecified address (why?).
+        r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
+        assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
+        assertEquals(Address("::"), r.getGateway());
+        assertEquals("lo", r.getInterface());
+
+        r = new RouteInfo(Prefix("192.0.2.5/24"), null);
+        assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
+        assertEquals(Address("0.0.0.0"), r.getGateway());
+        assertNull(r.getInterface());
+    }
+
+    public void testMatches() {
+        class PatchedRouteInfo extends RouteInfo {
+            public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
+                super(destination, gateway, iface);
+            }
+
+            public boolean matches(InetAddress destination) {
+                return super.matches(destination);
+            }
+        }
+
+        RouteInfo r;
+
+        r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
+        assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
+        assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
+        assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
+        assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
+        assertFalse(r.matches(Address("2001:4868:4860::8888")));
+
+        r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
+        assertTrue(r.matches(Address("192.0.2.43")));
+        assertTrue(r.matches(Address("192.0.3.21")));
+        assertFalse(r.matches(Address("192.0.0.21")));
+        assertFalse(r.matches(Address("8.8.8.8")));
+
+        RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
+        assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
+        assertFalse(ipv6Default.matches(Address("192.0.2.1")));
+
+        RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
+        assertTrue(ipv4Default.matches(Address("255.255.255.255")));
+        assertTrue(ipv4Default.matches(Address("192.0.2.1")));
+        assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
+    }
+
+    private void assertAreEqual(Object o1, Object o2) {
+        assertTrue(o1.equals(o2));
+        assertTrue(o2.equals(o1));
+    }
+
+    private void assertAreNotEqual(Object o1, Object o2) {
+        assertFalse(o1.equals(o2));
+        assertFalse(o2.equals(o1));
+    }
+
+    public void testEquals() {
+        // IPv4
+        RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
+        RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
+        assertAreEqual(r1, r2);
+
+        RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
+        RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
+        RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
+        assertAreNotEqual(r1, r3);
+        assertAreNotEqual(r1, r4);
+        assertAreNotEqual(r1, r5);
+
+        // IPv6
+        r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
+        r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
+        assertAreEqual(r1, r2);
+
+        r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
+        r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
+        r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
+        assertAreNotEqual(r1, r3);
+        assertAreNotEqual(r1, r4);
+        assertAreNotEqual(r1, r5);
+
+        // Interfaces (but not destinations or gateways) can be null.
+        r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
+        r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
+        r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
+        assertAreEqual(r1, r2);
+        assertAreNotEqual(r1, r3);
+    }
+
+    public void testHostRoute() {
+      RouteInfo r;
+
+      r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
+      assertFalse(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
+      assertFalse(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
+      assertFalse(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
+      assertFalse(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
+      assertTrue(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
+      assertTrue(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
+      assertTrue(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
+      assertTrue(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
+      assertTrue(r.isHostRoute());
+
+      r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
+      assertTrue(r.isHostRoute());
+    }
+
+    public RouteInfo passThroughParcel(RouteInfo r) {
+        Parcel p = Parcel.obtain();
+        RouteInfo r2 = null;
+        try {
+            r.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            r2 = RouteInfo.CREATOR.createFromParcel(p);
+        } finally {
+            p.recycle();
+        }
+        assertNotNull(r2);
+        return r2;
+    }
+
+    public void assertParcelingIsLossless(RouteInfo r) {
+      RouteInfo r2 = passThroughParcel(r);
+      assertEquals(r, r2);
+    }
+
+    public void testParceling() {
+        RouteInfo r;
+
+        r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null);
+        assertParcelingIsLossless(r);
+
+        r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
+        assertParcelingIsLossless(r);
+    }
+}
diff --git a/core/tests/coretests/src/android/net/UriMatcherTest.java b/core/tests/coretests/src/android/net/UriMatcherTest.java
index 2872144..a728d4f 100644
--- a/core/tests/coretests/src/android/net/UriMatcherTest.java
+++ b/core/tests/coretests/src/android/net/UriMatcherTest.java
@@ -19,10 +19,11 @@
 import android.content.UriMatcher;
 import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
+
 import junit.framework.TestCase;
 
-public class UriMatcherTest extends TestCase
-{
+public class UriMatcherTest extends TestCase {
+
     static final int ROOT = 0;
     static final int PEOPLE = 1;
     static final int PEOPLE_ID = 2;
@@ -37,54 +38,76 @@
     static final int CALLERID = 11;
     static final int CALLERID_TEXT = 12;
     static final int FILTERRECENT = 13;
-    
+    static final int ANOTHER_PATH_SEGMENT = 13;
+
     @SmallTest
     public void testContentUris() {
-        check("content://asdf", UriMatcher.NO_MATCH);
-        check("content://people", PEOPLE);
-        check("content://people/1", PEOPLE_ID);
-        check("content://people/asdf", UriMatcher.NO_MATCH);
-        check("content://people/2/phones", PEOPLE_PHONES); 
-        check("content://people/2/phones/3", PEOPLE_PHONES_ID); 
-        check("content://people/2/phones/asdf", UriMatcher.NO_MATCH);
-        check("content://people/2/addresses", PEOPLE_ADDRESSES); 
-        check("content://people/2/addresses/3", PEOPLE_ADDRESSES_ID); 
-        check("content://people/2/addresses/asdf", UriMatcher.NO_MATCH);
-        check("content://people/2/contact-methods", PEOPLE_CONTACTMETH); 
-        check("content://people/2/contact-methods/3", PEOPLE_CONTACTMETH_ID); 
-        check("content://people/2/contact-methods/asdf", UriMatcher.NO_MATCH);
-        check("content://calls", CALLS);
-        check("content://calls/1", CALLS_ID);
-        check("content://calls/asdf", UriMatcher.NO_MATCH);
-        check("content://caller-id", CALLERID);
-        check("content://caller-id/asdf", CALLERID_TEXT);
-        check("content://caller-id/1", CALLERID_TEXT);
-        check("content://filter-recent", FILTERRECENT);
+        UriMatcher matcher = new UriMatcher(ROOT);
+        matcher.addURI("people", null, PEOPLE);
+        matcher.addURI("people", "#", PEOPLE_ID);
+        matcher.addURI("people", "#/phones", PEOPLE_PHONES);
+        matcher.addURI("people", "#/phones/blah", PEOPLE_PHONES_ID);
+        matcher.addURI("people", "#/phones/#", PEOPLE_PHONES_ID);
+        matcher.addURI("people", "#/addresses", PEOPLE_ADDRESSES);
+        matcher.addURI("people", "#/addresses/#", PEOPLE_ADDRESSES_ID);
+        matcher.addURI("people", "#/contact-methods", PEOPLE_CONTACTMETH);
+        matcher.addURI("people", "#/contact-methods/#", PEOPLE_CONTACTMETH_ID);
+        matcher.addURI("calls", null, CALLS);
+        matcher.addURI("calls", "#", CALLS_ID);
+        matcher.addURI("caller-id", null, CALLERID);
+        matcher.addURI("caller-id", "*", CALLERID_TEXT);
+        matcher.addURI("filter-recent", null, FILTERRECENT);
+        matcher.addURI("auth", "another/path/segment", ANOTHER_PATH_SEGMENT);
+        checkAll(matcher);
     }
 
-    private static final UriMatcher mURLMatcher = new UriMatcher(ROOT);
-
-    static
-    {
-        mURLMatcher.addURI("people", null, PEOPLE);
-        mURLMatcher.addURI("people", "#", PEOPLE_ID);
-        mURLMatcher.addURI("people", "#/phones", PEOPLE_PHONES);
-        mURLMatcher.addURI("people", "#/phones/blah", PEOPLE_PHONES_ID);
-        mURLMatcher.addURI("people", "#/phones/#", PEOPLE_PHONES_ID);
-        mURLMatcher.addURI("people", "#/addresses", PEOPLE_ADDRESSES);
-        mURLMatcher.addURI("people", "#/addresses/#", PEOPLE_ADDRESSES_ID);
-        mURLMatcher.addURI("people", "#/contact-methods", PEOPLE_CONTACTMETH);
-        mURLMatcher.addURI("people", "#/contact-methods/#", PEOPLE_CONTACTMETH_ID);
-        mURLMatcher.addURI("calls", null, CALLS);
-        mURLMatcher.addURI("calls", "#", CALLS_ID);
-        mURLMatcher.addURI("caller-id", null, CALLERID);
-        mURLMatcher.addURI("caller-id", "*", CALLERID_TEXT);
-        mURLMatcher.addURI("filter-recent", null, FILTERRECENT);
+    @SmallTest
+    public void testContentUrisWithLeadingSlash() {
+        UriMatcher matcher = new UriMatcher(ROOT);
+        matcher.addURI("people", null, PEOPLE);
+        matcher.addURI("people", "/#", PEOPLE_ID);
+        matcher.addURI("people", "/#/phones", PEOPLE_PHONES);
+        matcher.addURI("people", "/#/phones/blah", PEOPLE_PHONES_ID);
+        matcher.addURI("people", "/#/phones/#", PEOPLE_PHONES_ID);
+        matcher.addURI("people", "/#/addresses", PEOPLE_ADDRESSES);
+        matcher.addURI("people", "/#/addresses/#", PEOPLE_ADDRESSES_ID);
+        matcher.addURI("people", "/#/contact-methods", PEOPLE_CONTACTMETH);
+        matcher.addURI("people", "/#/contact-methods/#", PEOPLE_CONTACTMETH_ID);
+        matcher.addURI("calls", null, CALLS);
+        matcher.addURI("calls", "/#", CALLS_ID);
+        matcher.addURI("caller-id", null, CALLERID);
+        matcher.addURI("caller-id", "/*", CALLERID_TEXT);
+        matcher.addURI("filter-recent", null, FILTERRECENT);
+        matcher.addURI("auth", "/another/path/segment", ANOTHER_PATH_SEGMENT);
+        checkAll(matcher);
     }
 
-    void check(String uri, int expected)
-    {
-        int result = mURLMatcher.match(Uri.parse(uri));
+    private void checkAll(UriMatcher matcher) {
+        check("content://asdf", UriMatcher.NO_MATCH, matcher);
+        check("content://people", PEOPLE, matcher);
+        check("content://people/1", PEOPLE_ID, matcher);
+        check("content://people/asdf", UriMatcher.NO_MATCH, matcher);
+        check("content://people/2/phones", PEOPLE_PHONES, matcher);
+        check("content://people/2/phones/3", PEOPLE_PHONES_ID, matcher);
+        check("content://people/2/phones/asdf", UriMatcher.NO_MATCH, matcher);
+        check("content://people/2/addresses", PEOPLE_ADDRESSES, matcher);
+        check("content://people/2/addresses/3", PEOPLE_ADDRESSES_ID, matcher);
+        check("content://people/2/addresses/asdf", UriMatcher.NO_MATCH, matcher);
+        check("content://people/2/contact-methods", PEOPLE_CONTACTMETH, matcher);
+        check("content://people/2/contact-methods/3", PEOPLE_CONTACTMETH_ID, matcher);
+        check("content://people/2/contact-methods/asdf", UriMatcher.NO_MATCH, matcher);
+        check("content://calls", CALLS, matcher);
+        check("content://calls/1", CALLS_ID, matcher);
+        check("content://calls/asdf", UriMatcher.NO_MATCH, matcher);
+        check("content://caller-id", CALLERID, matcher);
+        check("content://caller-id/asdf", CALLERID_TEXT, matcher);
+        check("content://caller-id/1", CALLERID_TEXT, matcher);
+        check("content://filter-recent", FILTERRECENT, matcher);
+        check("content://auth/another/path/segment", ANOTHER_PATH_SEGMENT, matcher);
+    }
+
+    private void check(String uri, int expected, UriMatcher matcher) {
+        int result = matcher.match(Uri.parse(uri));
         if (result != expected) {
             String msg = "failed on " + uri;
             msg += " expected " + expected + " got " + result;
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 4d0b892..0f2b803 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -16,61 +16,65 @@
 
 package android.os;
 
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+
 import android.content.Context;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import com.google.android.collect.Sets;
+
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
+import java.util.Arrays;
+import java.util.HashSet;
 
+import libcore.io.IoUtils;
+
+@MediumTest
 public class FileUtilsTest extends AndroidTestCase {
     private static final String TEST_DATA =
             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
+    private File mDir;
     private File mTestFile;
     private File mCopyFile;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        File testDir = getContext().getDir("testing", Context.MODE_PRIVATE);
-        mTestFile = new File(testDir, "test.file");
-        mCopyFile = new File(testDir, "copy.file");
-        FileWriter writer = new FileWriter(mTestFile);
-        try {
-            writer.write(TEST_DATA, 0, TEST_DATA.length());
-        } finally {
-            writer.close();
-        }
+        mDir = getContext().getDir("testing", Context.MODE_PRIVATE);
+        mTestFile = new File(mDir, "test.file");
+        mCopyFile = new File(mDir, "copy.file");
     }
 
     @Override
     protected void tearDown() throws Exception {
-        if (mTestFile.exists()) mTestFile.delete();
-        if (mCopyFile.exists()) mCopyFile.delete();
+        IoUtils.deleteContents(mDir);
     }
 
     // TODO: test setPermissions(), getPermissions()
 
-    @MediumTest
     public void testCopyFile() throws Exception {
+        stageFile(mTestFile, TEST_DATA);
         assertFalse(mCopyFile.exists());
         FileUtils.copyFile(mTestFile, mCopyFile);
         assertTrue(mCopyFile.exists());
         assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null));
     }
 
-    @MediumTest
     public void testCopyToFile() throws Exception {
         final String s = "Foo Bar";
         assertFalse(mCopyFile.exists());
-        FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile);        assertTrue(mCopyFile.exists());
+        FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile);
+        assertTrue(mCopyFile.exists());
         assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null));
     }
 
-    @MediumTest
     public void testIsFilenameSafe() throws Exception {
         assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
         assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
@@ -78,8 +82,9 @@
         assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar")));
     }
 
-    @MediumTest
     public void testReadTextFile() throws Exception {
+        stageFile(mTestFile, TEST_DATA);
+
         assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null));
 
         assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null));
@@ -97,8 +102,8 @@
         assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>"));
     }
 
-    @MediumTest
     public void testReadTextFileWithZeroLengthFile() throws Exception {
+        stageFile(mTestFile, TEST_DATA);
         new FileOutputStream(mTestFile).close();  // Zero out the file
         assertEquals("", FileUtils.readTextFile(mTestFile, 0, null));
         assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>"));
@@ -106,4 +111,81 @@
         assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>"));
         assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>"));
     }
+
+    public void testDeleteOlderEmptyDir() throws Exception {
+        FileUtils.deleteOlderFiles(mDir, 10, WEEK_IN_MILLIS);
+        assertDirContents();
+    }
+
+    public void testDeleteOlderTypical() throws Exception {
+        touch("file1", HOUR_IN_MILLIS);
+        touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS);
+        assertDirContents("file1", "file2", "file3");
+    }
+
+    public void testDeleteOlderInFuture() throws Exception {
+        touch("file1", -HOUR_IN_MILLIS);
+        touch("file2", HOUR_IN_MILLIS);
+        touch("file3", WEEK_IN_MILLIS);
+        FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+        assertDirContents("file1", "file2");
+
+        touch("file1", -HOUR_IN_MILLIS);
+        touch("file2", HOUR_IN_MILLIS);
+        touch("file3", WEEK_IN_MILLIS);
+        FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+        assertDirContents("file1", "file2");
+    }
+
+    public void testDeleteOlderOnlyAge() throws Exception {
+        touch("file1", HOUR_IN_MILLIS);
+        touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS);
+        assertDirContents("file1");
+    }
+
+    public void testDeleteOlderOnlyCount() throws Exception {
+        touch("file1", HOUR_IN_MILLIS);
+        touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS);
+        FileUtils.deleteOlderFiles(mDir, 2, 0);
+        assertDirContents("file1", "file2");
+    }
+
+    private void touch(String name, long age) throws Exception {
+        final File file = new File(mDir, name);
+        file.createNewFile();
+        file.setLastModified(System.currentTimeMillis() - age);
+    }
+
+    private void stageFile(File file, String data) throws Exception {
+        FileWriter writer = new FileWriter(file);
+        try {
+            writer.write(data, 0, data.length());
+        } finally {
+            writer.close();
+        }
+    }
+
+    private void assertDirContents(String... expected) {
+        final HashSet<String> expectedSet = Sets.newHashSet(expected);
+        String[] actual = mDir.list();
+        if (actual == null) actual = new String[0];
+
+        assertEquals(
+                "Expected " + Arrays.toString(expected) + " but actual " + Arrays.toString(actual),
+                expected.length, actual.length);
+        for (String actualFile : actual) {
+            assertTrue("Unexpected actual file " + actualFile, expectedSet.contains(actualFile));
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index cf42bb1..c5f6236 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -21,8 +21,9 @@
 import junit.framework.TestCase;
 
 public class DateUtilsTest extends TestCase {
+    // This test is not in CTS because formatDuration is @hidden.
     @SmallTest
-    public void testFormatDurationSeconds() throws Exception {
+    public void test_formatDuration_seconds() throws Exception {
         assertEquals("0 seconds", DateUtils.formatDuration(0));
         assertEquals("0 seconds", DateUtils.formatDuration(1));
         assertEquals("0 seconds", DateUtils.formatDuration(499));
@@ -31,16 +32,18 @@
         assertEquals("2 seconds", DateUtils.formatDuration(1500));
     }
 
+    // This test is not in CTS because formatDuration is @hidden.
     @SmallTest
-    public void testFormatDurationMinutes() throws Exception {
+    public void test_formatDuration_Minutes() throws Exception {
         assertEquals("59 seconds", DateUtils.formatDuration(59000));
         assertEquals("60 seconds", DateUtils.formatDuration(59500));
         assertEquals("1 minute", DateUtils.formatDuration(60000));
         assertEquals("2 minutes", DateUtils.formatDuration(120000));
     }
 
+    // This test is not in CTS because formatDuration is @hidden.
     @SmallTest
-    public void testFormatDurationHours() throws Exception {
+    public void test_formatDuration_Hours() throws Exception {
         assertEquals("59 minutes", DateUtils.formatDuration(3540000));
         assertEquals("1 hour", DateUtils.formatDuration(3600000));
         assertEquals("48 hours", DateUtils.formatDuration(172800000));
diff --git a/core/tests/coretests/src/android/webkit/WebkitTest.java b/core/tests/coretests/src/android/webkit/WebkitTest.java
index 17b4088..4685e3c 100644
--- a/core/tests/coretests/src/android/webkit/WebkitTest.java
+++ b/core/tests/coretests/src/android/webkit/WebkitTest.java
@@ -52,7 +52,7 @@
             date.setTime(time);
             c.setTime(date);
             index = dateSorter.getIndex(time);
-            Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd kk:mm:ss", c).toString() +
+            Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd HH:mm:ss", c).toString() +
                     " " + index + " " + dateSorter.getLabel(index));
         }
     }
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
index 9c44d61..0518e64 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
@@ -265,8 +265,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleSwitching() throws Exception {
-        String filename = DOWNLOAD_500K_FILENAME;
-        long filesize = DOWNLOAD_500K_FILESIZE;
+        String filename = DOWNLOAD_5MB_FILENAME;
+        long filesize = DOWNLOAD_5MB_FILESIZE;
         doCommonDownloadSetup();
 
         String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
@@ -340,8 +340,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleWiFiEnableDisable() throws Exception {
-        String filename = DOWNLOAD_500K_FILENAME;
-        long filesize = DOWNLOAD_500K_FILESIZE;
+        String filename = DOWNLOAD_5MB_FILENAME;
+        long filesize = DOWNLOAD_5MB_FILESIZE;
         doCommonDownloadSetup();
 
         String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
@@ -409,8 +409,8 @@
      * @throws Exception if unsuccessful
      */
     public void runDownloadMultipleAirplaneModeEnableDisable() throws Exception {
-        String filename = DOWNLOAD_500K_FILENAME;
-        long filesize = DOWNLOAD_500K_FILESIZE;
+        String filename = DOWNLOAD_5MB_FILENAME;
+        long filesize = DOWNLOAD_5MB_FILESIZE;
         // make sure WiFi is enabled, and airplane mode is not on
         doCommonDownloadSetup();
 
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index e02e95a..7f8d5f0 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -152,7 +152,7 @@
     RobotoCondensed-Italic.ttf \
     RobotoCondensed-BoldItalic.ttf \
     DroidNaskh-Regular.ttf \
-    DroidNaskh-Regular-SystemUI.ttf \
+    DroidNaskhUI-Regular.ttf \
     DroidSansDevanagari-Regular.ttf \
     DroidSansHebrew-Regular.ttf \
     DroidSansHebrew-Bold.ttf \
diff --git a/data/fonts/DroidNaskh-Regular-SystemUI.ttf b/data/fonts/DroidNaskhUI-Regular.ttf
similarity index 100%
rename from data/fonts/DroidNaskh-Regular-SystemUI.ttf
rename to data/fonts/DroidNaskhUI-Regular.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Bold.ttf b/data/fonts/DroidSerif-Bold.ttf
index 838d255..16a914e 100644
--- a/data/fonts/DroidSerif-Bold.ttf
+++ b/data/fonts/DroidSerif-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-BoldItalic.ttf b/data/fonts/DroidSerif-BoldItalic.ttf
index 0b1601f..50324fc 100644
--- a/data/fonts/DroidSerif-BoldItalic.ttf
+++ b/data/fonts/DroidSerif-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Italic.ttf b/data/fonts/DroidSerif-Italic.ttf
index 2972809..bb2757c 100644
--- a/data/fonts/DroidSerif-Italic.ttf
+++ b/data/fonts/DroidSerif-Italic.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Regular.ttf b/data/fonts/DroidSerif-Regular.ttf
index 5b4fe81..da0a2cc 100644
--- a/data/fonts/DroidSerif-Regular.ttf
+++ b/data/fonts/DroidSerif-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Bold.ttf b/data/fonts/Roboto-Bold.ttf
index 40ecd14..072b842 100644
--- a/data/fonts/Roboto-Bold.ttf
+++ b/data/fonts/Roboto-Bold.ttf
Binary files differ
diff --git a/data/fonts/Roboto-BoldItalic.ttf b/data/fonts/Roboto-BoldItalic.ttf
index d9067c5..74919ff 100644
--- a/data/fonts/Roboto-BoldItalic.ttf
+++ b/data/fonts/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Italic.ttf b/data/fonts/Roboto-Italic.ttf
index 88e4a5b..bd57775 100644
--- a/data/fonts/Roboto-Italic.ttf
+++ b/data/fonts/Roboto-Italic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Light.ttf b/data/fonts/Roboto-Light.ttf
index 2ae4dec..13bf13a 100644
--- a/data/fonts/Roboto-Light.ttf
+++ b/data/fonts/Roboto-Light.ttf
Binary files differ
diff --git a/data/fonts/Roboto-LightItalic.ttf b/data/fonts/Roboto-LightItalic.ttf
index 44177ef..130672a 100644
--- a/data/fonts/Roboto-LightItalic.ttf
+++ b/data/fonts/Roboto-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Regular.ttf b/data/fonts/Roboto-Regular.ttf
index f592adf..0ba95c9 100644
--- a/data/fonts/Roboto-Regular.ttf
+++ b/data/fonts/Roboto-Regular.ttf
Binary files differ
diff --git a/data/fonts/Roboto-Thin.ttf b/data/fonts/Roboto-Thin.ttf
index 5ae4d7f..309c22d 100644
--- a/data/fonts/Roboto-Thin.ttf
+++ b/data/fonts/Roboto-Thin.ttf
Binary files differ
diff --git a/data/fonts/Roboto-ThinItalic.ttf b/data/fonts/Roboto-ThinItalic.ttf
index 9cd3927..0b53ba4 100644
--- a/data/fonts/Roboto-ThinItalic.ttf
+++ b/data/fonts/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Bold.ttf b/data/fonts/RobotoCondensed-Bold.ttf
index 21c10f5..f0fd409 100644
--- a/data/fonts/RobotoCondensed-Bold.ttf
+++ b/data/fonts/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-BoldItalic.ttf b/data/fonts/RobotoCondensed-BoldItalic.ttf
index d8edd2d..e67b02b 100644
--- a/data/fonts/RobotoCondensed-BoldItalic.ttf
+++ b/data/fonts/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Italic.ttf b/data/fonts/RobotoCondensed-Italic.ttf
index 4dec2cf..a08414b 100644
--- a/data/fonts/RobotoCondensed-Italic.ttf
+++ b/data/fonts/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-Regular.ttf b/data/fonts/RobotoCondensed-Regular.ttf
index 875ea1a..713fd30 100644
--- a/data/fonts/RobotoCondensed-Regular.ttf
+++ b/data/fonts/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 999ddc4..16d760c 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -36,7 +36,7 @@
     </family>
     <family>
         <fileset>
-            <file variant="compact">DroidNaskh-Regular-SystemUI.ttf</file>
+            <file variant="compact">DroidNaskhUI-Regular.ttf</file>
         </fileset>
     </family>
     <family>
@@ -78,17 +78,50 @@
     </family>
     <family>
         <fileset>
-            <file>AnjaliNewLipi-light.ttf</file>
+            <file variant="elegant">NotoSansMalayalam-Regular.ttf</file>
+            <file variant="elegant">NotoSansMalayalam-Bold.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file>Lohit-Bengali.ttf</file>
+            <file variant="compact">NotoSansMalayalamUI-Regular.ttf</file>
+            <file variant="compact">NotoSansMalayalamUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
-            <file>Lohit-Kannada.ttf</file>
+            <file variant="elegant">NotoSansBengali-Regular.ttf</file>
+            <file variant="elegant">NotoSansBengali-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansBengaliUI-Regular.ttf</file>
+            <file variant="compact">NotoSansBengaliUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="elegant">NotoSansTelugu-Regular.ttf</file>
+            <file variant="elegant">NotoSansTelugu-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansTeluguUI-Regular.ttf</file>
+            <file variant="compact">NotoSansTeluguUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="elegant">NotoSansKannada-Regular.ttf</file>
+            <file variant="elegant">NotoSansKannada-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansKannadaUI-Regular.ttf</file>
+            <file variant="compact">NotoSansKannadaUI-Bold.ttf</file>
         </fileset>
     </family>
     <family>
@@ -103,11 +136,6 @@
     </family>
     <family>
         <fileset>
-            <file>Lohit-Telugu.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
             <file>DroidSansFallback.ttf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 875795a..7c2f955 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -33,7 +33,7 @@
     RobotoCondensed-Italic.ttf \
     RobotoCondensed-BoldItalic.ttf \
     DroidNaskh-Regular.ttf \
-    DroidNaskh-Regular-SystemUI.ttf \
+    DroidNaskhUI-Regular.ttf \
     DroidSansDevanagari-Regular.ttf \
     DroidSansHebrew-Regular.ttf \
     DroidSansHebrew-Bold.ttf \
diff --git a/data/sounds/AllAudio.mk b/data/sounds/AllAudio.mk
index e403205..8b03bf7 100644
--- a/data/sounds/AllAudio.mk
+++ b/data/sounds/AllAudio.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2009 The Android Open Source Project
+# 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.
@@ -12,13 +11,222 @@
 # 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.
-#
 
-$(call inherit-product, frameworks/base/data/sounds/OriginalAudio.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage2.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage3.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage4.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage5.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage6.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage7.mk)
-$(call inherit-product, frameworks/base/data/sounds/AudioPackage7alt.mk)
+LOCAL_PATH := frameworks/base/data/sounds
+
+PRODUCT_COPY_FILES += \
+    $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
+    $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
+    $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
+    $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
+    $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
+    $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
+    $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
+    $(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \
+    $(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
+    $(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \
+    $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \
+    $(LOCAL_PATH)/notifications/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \
+    $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg \
+    $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
+    $(LOCAL_PATH)/notifications/Castor.ogg:system/media/audio/notifications/Castor.ogg \
+    $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:system/media/audio/notifications/Cobalt.ogg \
+    $(LOCAL_PATH)/notifications/Cricket.ogg:system/media/audio/notifications/Cricket.ogg \
+    $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
+    $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \
+    $(LOCAL_PATH)/notifications/Doink.ogg:system/media/audio/notifications/Doink.ogg \
+    $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
+    $(LOCAL_PATH)/notifications/Drip.ogg:system/media/audio/notifications/Drip.ogg \
+    $(LOCAL_PATH)/notifications/Electra.ogg:system/media/audio/notifications/Electra.ogg \
+    $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
+    $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
+    $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:system/media/audio/notifications/Fluorine.ogg \
+    $(LOCAL_PATH)/notifications/Fomalhaut.ogg:system/media/audio/notifications/Fomalhaut.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:system/media/audio/notifications/Gallium.ogg \
+    $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Helium.ogg:system/media/audio/notifications/Helium.ogg \
+    $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:system/media/audio/notifications/Krypton.ogg \
+    $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \
+    $(LOCAL_PATH)/notifications/Merope.ogg:system/media/audio/notifications/Merope.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
+    $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:system/media/audio/notifications/Palladium.ogg \
+    $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:system/media/audio/notifications/Plastic_Pipe.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Radon.ogg:system/media/audio/notifications/Radon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:system/media/audio/notifications/Rubidium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:system/media/audio/notifications/Selenium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
+    $(LOCAL_PATH)/notifications/Sirrah.ogg:system/media/audio/notifications/Sirrah.ogg \
+    $(LOCAL_PATH)/notifications/SpaceSeed.ogg:system/media/audio/notifications/SpaceSeed.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:system/media/audio/notifications/Strontium.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
+    $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
+    $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
+    $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \
+    $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \
+    $(LOCAL_PATH)/notifications/arcturus.ogg:system/media/audio/notifications/arcturus.ogg \
+    $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
+    $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
+    $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
+    $(LOCAL_PATH)/notifications/regulus.ogg:system/media/audio/notifications/regulus.ogg \
+    $(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \
+    $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
+    $(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg \
+    $(LOCAL_PATH)/ringtones/ANDROMEDA.ogg:system/media/audio/ringtones/ANDROMEDA.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Atria.ogg:system/media/audio/ringtones/Atria.ogg \
+    $(LOCAL_PATH)/ringtones/BOOTES.ogg:system/media/audio/ringtones/BOOTES.ogg \
+    $(LOCAL_PATH)/newwavelabs/Backroad.ogg:system/media/audio/ringtones/Backroad.ogg \
+    $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
+    $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
+    $(LOCAL_PATH)/newwavelabs/Big_Easy.ogg:system/media/audio/ringtones/Big_Easy.ogg \
+    $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
+    $(LOCAL_PATH)/newwavelabs/Bollywood.ogg:system/media/audio/ringtones/Bollywood.ogg \
+    $(LOCAL_PATH)/newwavelabs/BussaMove.ogg:system/media/audio/ringtones/BussaMove.ogg \
+    $(LOCAL_PATH)/ringtones/CANISMAJOR.ogg:system/media/audio/ringtones/CANISMAJOR.ogg \
+    $(LOCAL_PATH)/ringtones/CASSIOPEIA.ogg:system/media/audio/ringtones/CASSIOPEIA.ogg \
+    $(LOCAL_PATH)/newwavelabs/Cairo.ogg:system/media/audio/ringtones/Cairo.ogg \
+    $(LOCAL_PATH)/newwavelabs/Calypso_Steel.ogg:system/media/audio/ringtones/Calypso_Steel.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
+    $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
+    $(LOCAL_PATH)/newwavelabs/Champagne_Edition.ogg:system/media/audio/ringtones/Champagne_Edition.ogg \
+    $(LOCAL_PATH)/newwavelabs/Club_Cubano.ogg:system/media/audio/ringtones/Club_Cubano.ogg \
+    $(LOCAL_PATH)/newwavelabs/CrayonRock.ogg:system/media/audio/ringtones/CrayonRock.ogg \
+    $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
+    $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
+    $(LOCAL_PATH)/newwavelabs/DancinFool.ogg:system/media/audio/ringtones/DancinFool.ogg \
+    $(LOCAL_PATH)/newwavelabs/Ding.ogg:system/media/audio/ringtones/Ding.ogg \
+    $(LOCAL_PATH)/newwavelabs/DonMessWivIt.ogg:system/media/audio/ringtones/DonMessWivIt.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
+    $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg \
+    $(LOCAL_PATH)/newwavelabs/Eastern_Sky.ogg:system/media/audio/ringtones/Eastern_Sky.ogg \
+    $(LOCAL_PATH)/newwavelabs/Enter_the_Nexus.ogg:system/media/audio/ringtones/Enter_the_Nexus.ogg \
+    $(LOCAL_PATH)/ringtones/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \
+    $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
+    $(LOCAL_PATH)/ringtones/FreeFlight.ogg:system/media/audio/ringtones/FreeFlight.ogg \
+    $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \
+    $(LOCAL_PATH)/newwavelabs/Funk_Yall.ogg:system/media/audio/ringtones/Funk_Yall.ogg \
+    $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \
+    $(LOCAL_PATH)/newwavelabs/Gimme_Mo_Town.ogg:system/media/audio/ringtones/Gimme_Mo_Town.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Girtab.ogg:system/media/audio/ringtones/Girtab.ogg \
+    $(LOCAL_PATH)/newwavelabs/Glacial_Groove.ogg:system/media/audio/ringtones/Glacial_Groove.ogg \
+    $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
+    $(LOCAL_PATH)/newwavelabs/HalfwayHome.ogg:system/media/audio/ringtones/HalfwayHome.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/Hydra.ogg \
+    $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Kuma.ogg:system/media/audio/ringtones/Kuma.ogg \
+    $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
+    $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
+    $(LOCAL_PATH)/ringtones/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
+    $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
+    $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
+    $(LOCAL_PATH)/newwavelabs/Nairobi.ogg:system/media/audio/ringtones/Nairobi.ogg \
+    $(LOCAL_PATH)/newwavelabs/Nassau.ogg:system/media/audio/ringtones/Nassau.ogg \
+    $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
+    $(LOCAL_PATH)/newwavelabs/No_Limits.ogg:system/media/audio/ringtones/No_Limits.ogg \
+    $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \
+    $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
+    $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
+    $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
+    $(LOCAL_PATH)/ringtones/PERSEUS.ogg:system/media/audio/ringtones/PERSEUS.ogg \
+    $(LOCAL_PATH)/newwavelabs/Paradise_Island.ogg:system/media/audio/ringtones/Paradise_Island.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
+    $(LOCAL_PATH)/newwavelabs/Playa.ogg:system/media/audio/ringtones/Playa.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Rasalas.ogg:system/media/audio/ringtones/Rasalas.ogg \
+    $(LOCAL_PATH)/newwavelabs/Revelation.ogg:system/media/audio/ringtones/Revelation.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
+    $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
+    $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
+    $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
+    $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
+    $(LOCAL_PATH)/newwavelabs/Road_Trip.ogg:system/media/audio/ringtones/Road_Trip.ogg \
+    $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \
+    $(LOCAL_PATH)/newwavelabs/Safari.ogg:system/media/audio/ringtones/Safari.ogg \
+    $(LOCAL_PATH)/newwavelabs/Savannah.ogg:system/media/audio/ringtones/Savannah.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
+    $(LOCAL_PATH)/newwavelabs/Seville.ogg:system/media/audio/ringtones/Seville.ogg \
+    $(LOCAL_PATH)/newwavelabs/Shes_All_That.ogg:system/media/audio/ringtones/Shes_All_That.ogg \
+    $(LOCAL_PATH)/newwavelabs/SilkyWay.ogg:system/media/audio/ringtones/SilkyWay.ogg \
+    $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
+    $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \
+    $(LOCAL_PATH)/newwavelabs/Steppin_Out.ogg:system/media/audio/ringtones/Steppin_Out.ogg \
+    $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
+    $(LOCAL_PATH)/ringtones/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Themos.ogg:system/media/audio/ringtones/Themos.ogg \
+    $(LOCAL_PATH)/newwavelabs/Third_Eye.ogg:system/media/audio/ringtones/Third_Eye.ogg \
+    $(LOCAL_PATH)/newwavelabs/Thunderfoot.ogg:system/media/audio/ringtones/Thunderfoot.ogg \
+    $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
+    $(LOCAL_PATH)/ringtones/URSAMINOR.ogg:system/media/audio/ringtones/URSAMINOR.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
+    $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
+    $(LOCAL_PATH)/ringtones/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg \
+    $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
+    $(LOCAL_PATH)/ringtones/ogg/Zeta.ogg:system/media/audio/ringtones/Zeta.ogg \
+    $(LOCAL_PATH)/ringtones/hydra.ogg:system/media/audio/ringtones/hydra.ogg \
+    $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+    $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+    $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
+    $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
+    $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
+    $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+    $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
+    $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
+    $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
+    $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
+
diff --git a/data/sounds/generate-all-audio.sh b/data/sounds/generate-all-audio.sh
new file mode 100755
index 0000000..6f42f5a
--- /dev/null
+++ b/data/sounds/generate-all-audio.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+# 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 script regenerates AllAudio.mk based on the content of the other
+# makefiles.
+
+# It needs to be run from its location in the source tree.
+
+cat > AllAudio.mk << EOF
+# 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.
+
+LOCAL_PATH := frameworks/base/data/sounds
+
+PRODUCT_COPY_FILES += \\
+EOF
+
+cat OriginalAudio.mk AudioPackage*.mk |
+  grep \\\$\(LOCAL_PATH\).*: |
+  cut -d : -f 2 |
+  cut -d \  -f 1 |
+  sort -u |
+  while read DEST
+  do
+    echo -n \ \ \ \  >> AllAudio.mk
+    cat *.mk |
+      grep \\\$\(LOCAL_PATH\).*:$DEST |
+      tr -d \ \\t |
+      cut -d : -f 1 |
+      sort -u |
+      tail -n 1 |
+      tr -d \\n >> AllAudio.mk
+    echo :$DEST\ \\ >> AllAudio.mk
+  done
+echo >> AllAudio.mk
diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index 61b537d..48bea78 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/downloads/training/InteractiveChart.zip b/docs/downloads/training/InteractiveChart.zip
new file mode 100644
index 0000000..95248ad
--- /dev/null
+++ b/docs/downloads/training/InteractiveChart.zip
Binary files differ
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 93876f8..e17a0fd 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -1,107 +1,65 @@
 page.title=Dashboards
-header.hide=1
 @jd:body
 
+<style>
+div.chart,
+div.screens-chart {
+  display:none;
+}
+tr .total {
+  background-color:transparent;
+  border:0;
+  color:#666;
+}
+tr th.total {
+  font-weight:bold;
+}
+</style>
+
+
+
+
+<div class="sidebox">
+<h2>Google Play Install Stats</h2>
+<p>The Google Play Developer Console also provides <a
+href="{@docRoot}distribute/googleplay/about/distribution.html#stats">detailed statistics</a>
+about your users' devices. Those stats may help you prioritize the device profiles for which
+you optimize your app.</p>
+</div>
+
+<p>This page provides information about the relative number of devices that share a certain
+characteristic, such as Android version or screen size. This information may
+help you prioritize efforts for <a
+href="{@docRoot}training/basics/supporting-devices/index.html">supporting different devices</a>.</p>
+
+<p>Each snapshot of data represents all the devices that visited the Google Play Store in the
+prior 14 days.</p>
+
+<p class="note"><strong>Note:</strong> Beginning in April, 2013, these charts are now built
+using data collected from each device when the user visits the Google Play Store. Previously, the
+data was collected when the device simply checked-in to Google servers. We believe the new
+data more accurately reflects those users who are most engaged in the Android and Google Play
+ecosystem.</p>
 
 
 <h2 id="Platform">Platform Versions</h2>
 
-<p>This page provides data about the relative number of active devices
-running a given version of the Android platform. This can help you
-understand the landscape of device distribution and decide how to prioritize
-the development of your application features for the devices currently in
-the hands of users. For information about how to target your application to devices based on
-platform version, read about <a 
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API levels</a>.</p>
+<p>This section provides data about the relative number of devices running a given version of
+the Android platform.</p>
+
+<p>For information about how to target your application to devices based on
+platform version, read <a 
+href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different
+Platform Versions</a>.</p>
 
 
-<h3 id="PlatformCurrent">Current Distribution</h3>
-
-<p>The following pie chart and table is based on the number of Android devices that have accessed
-Google Play within a 14-day period ending on the data collection date noted below.</p>
-
-<div class="col-5" style="margin-left:0">
-
-
-<table>
-<tr>
-  <th>Version</th>
-  <th>Codename</th>
-  <th>API</th>
-  <th>Distribution</th>
-</tr>
-<tr><td><a href="/about/versions/android-1.6.html">1.6</a></td><td>Donut</td>    <td>4</td><td>0.2%</td></tr>
-<tr><td><a href="/about/versions/android-2.1.html">2.1</a></td><td>Eclair</td>   <td>7</td><td>1.9%</td></tr>
-<tr><td><a href="/about/versions/android-2.2.html">2.2</a></td><td>Froyo</td>    <td>8</td><td>7.6%</td></tr>
-<tr><td><a href="/about/versions/android-2.3.html">2.3 - 2.3.2</a>
-                                   </td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.2%</td></tr>
-<tr><td><a href="/about/versions/android-2.3.3.html">2.3.3 - 2.3.7
-        </a></td><!-- Gingerbread -->                                       <td>10</td><td>44%</td></tr>
-<tr><td><a href="/about/versions/android-3.1.html">3.1</a></td>
-                                                   <td rowspan="2">Honeycomb</td>      <td>12</td><td>0.3%</td></tr>
-<tr><td><a href="/about/versions/android-3.2.html">3.2</a></td>      <!-- Honeycomb --><td>13</td><td>0.9%</td></tr>
-<tr><td><a href="/about/versions/android-4.0.3.html">4.0.3 - 4.0.4</a></td>
-                                                            <td>Ice Cream Sandwich</td><td>15</td><td>28.6%</td></tr> 
-<tr><td><a href="/about/versions/android-4.1.html">4.1</a></td>
-                                                   <td rowspan="2">Jelly Bean</td><td>16</td><td>14.9%</td></tr>
-<tr><td><a href="/about/versions/android-4.2.html">4.2</a></td><!--Jelly Bean-->  <td>17</td><td>1.6%</td></tr>  
-</table>
-
+<div id="version-chart">
 </div>
 
-<div class="col-8" style="margin-right:0">
-<img style="margin-left:30px" alt=""
-src="//chart.apis.google.com/chart?&cht=p&chs=460x245&chf=bg,s,00000000&chd=t:2.0,7.6,44.2,1.2,28.6,16.5&chl=Eclair%20%26%20older|Froyo|Gingerbread|Honeycomb|Ice%20Cream%20Sandwich|Jelly%20Bean&chco=c4df9b,6fad0c"
-/>
 
-</div><!-- end dashboard-panel -->
-
-<p style="clear:both"><em>Data collected during a 14-day period ending on March 4, 2013</em></p>
-<!--
-<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
--->
-
-<h3 id="PlatformHistorical">Historical Distribution</h3>
-
-<p>The following stacked line graph provides a history of the relative number of
-active Android devices running different versions of the Android platform. It also provides a
-valuable perspective of how many devices your application is compatible with, based on the
-platform version.</p>
-
-<p>Notice that the platform versions are stacked on top of each other with the oldest active
-version at the top. This format indicates the total percent of active devices that are compatible
-with a given version of Android. For example, if you develop your application for
-the version that is at the very top of the chart, then your application is
-compatible with 100% of active devices (and all future versions), because all Android APIs are
-forward compatible. Or, if you develop your application for a version lower on the chart,
-then it is currently compatible with the percentage of devices indicated on the y-axis, where the
-line for that version meets the y-axis on the right.</p>
-
-<p>Each dataset in the timeline is based on the number of Android devices that accessed
-Google Play within a 14-day period ending on the date indicated on the x-axis.</p>
-
-<img alt="" height="250" width="660"
-src="//chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chf=bg,s,00000000&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C1%3A%7C2012%7C%7C%7C%7C%7C%7C%7C%7C2013%7C%7C%7C%7C2013%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.3,99.4,99.5,99.5,99.5,99.6,100.0,100.0,100.0,100.0,100.0,100.0,100.0|95.6,95.8,96.1,96.3,96.4,96.7,96.9,97.2,97.4,97.4,97.6,97.7,97.9|81.4,82.3,83.2,83.8,84.7,85.6,86.4,87.0,88.2,88.8,89.4,89.9,90.3|23.7,25.5,27.4,28.7,31.1,33.0,35.4,36.8,40.3,42.0,43.6,45.1,46.0|21.5,23.5,25.5,26.8,29.4,31.4,33.8,35.2,38.8,40.7,42.3,43.9,44.8|1.1,1.4,1.8,2.1,3.2,4.8,6.5,7.5,9.9,11.7,13.3,14.8,16.1&chm=b,c3df9b,0,1,0|tFroyo,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tGingerbread,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|b,96dd28,3,4,0|tIce%20Cream%20Sandwich,293f07,4,0,15,,t::-5|b,83c916,4,5,0|tJelly%20Bean,131d02,5,9,15,,t::-5|B,6fad0c,5,6,0&chg=7,25&chdl=Eclair|Froyo|Gingerbread|Honeycomb|Ice%20Cream%20Sandwich|Jelly%20Bean&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08"
-/>
-<p><em>Last historical dataset collected during a 14-day period ending on March 1, 2013</em></p>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+<p style="clear:both"><em>Data collected during a 14-day period ending on April 2, 2013.
+<br/>Any versions with less than 0.1% distribution are not shown.</em>
+</p>
 
 
 
@@ -111,72 +69,22 @@
 <h2 id="Screens">Screen Sizes and Densities</h2>
 
 
-<img alt="" style="float:right;"
-src="//chart.googleapis.com/chart?cht=p&chs=400x250&chf=bg,s,00000000&chco=c4df9b,6fad0c&chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.6,6.1,86.6,2.7" />
-
-
-<img alt="" style="float:right;clear:right"
-src="//chart.googleapis.com/chart?cht=p&chs=400x250&chf=bg,s,00000000&chco=c4df9b,6fad0c&chl=ldpi%7Cmdpi%7Chdpi%7Cxhdpi&chd=t%3A2.2,18,51.1,28.7" />
-
-
-<p>This section provides data about the relative number of active devices that have a particular
+<p>This section provides data about the relative number of devices that have a particular
 screen configuration, defined by a combination of screen size and density. To simplify the way that
 you design your user interfaces for different screen configurations, Android divides the range of
-actual screen sizes and densities into:</p> 
- 
-<ul> 
-<li>A set of four generalized <strong>sizes</strong>: <em>small</em>, <em>normal</em>,
-<em>large</em>, and <em>xlarge</em></em></li>
-<li>A set of four generalized <strong>densities</strong>: <em>ldpi</em> (low), <em>mdpi</em>
-(medium), <em>hdpi</em> (high), and <em>xhdpi</em> (extra high)</li>
-</ul> 
+actual screen sizes and densities into several buckets as expressed by the table below.</p>
 
 <p>For information about how you can support multiple screen configurations in your
-application, see <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+application, read <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
 Screens</a>.</p>
 
-<p class="note"><strong>Note:</strong> This data is based on the number
-of Android devices that have accessed Google Play within a 7-day period
-ending on the data collection date noted below.</p>
+
+<div id="screens-chart">
+</div>
 
 
-<table style="width:350px">
-<tr>
-<th></th>
-<th scope="col">ldpi</th>
-<th scope="col">mdpi</th>
-<th scope="col">hdpi</th>
-<th scope="col">xhdpi</th>
-</tr>
-<tr><th scope="row">small</th> 
-<td>1.7%</td>     <!-- small/ldpi -->
-<td></td>     <!-- small/mdpi -->
-<td>1.0%</td> <!-- small/hdpi -->
-<td></td>     <!-- small/xhdpi -->
-</tr> 
-<tr><th scope="row">normal</th> 
-<td>0.4%</td>  <!-- normal/ldpi -->
-<td>11%</td> <!-- normal/mdpi -->
-<td>50.1%</td> <!-- normal/hdpi -->
-<td>25.1%</td>      <!-- normal/xhdpi -->
-</tr> 
-<tr><th scope="row">large</th> 
-<td>0.1%</td>     <!-- large/ldpi -->
-<td>2.4%</td> <!-- large/mdpi -->
-<td></td>     <!-- large/hdpi -->
-<td>3.6%</td>     <!-- large/xhdpi -->
-</tr> 
-<tr><th scope="row">xlarge</th> 
-<td></td>     <!-- xlarge/ldpi -->
-<td>4.6%</td> <!-- xlarge/mdpi -->
-<td></td>     <!-- xlarge/hdpi -->
-<td></td>     <!-- xlarge/xhdpi -->
-</tr> 
-</table>
-
-<p style="clear:both"><em>Data collected during a 7-day period ending on October 1, 2012</em></p>
-
-
+<p style="clear:both"><em>Data collected during a 14-day period ending on April 2, 2013
+<br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
 
@@ -187,14 +95,14 @@
 
 <h2 id="OpenGL">Open GL Version</h2>
 
-<p>This section provides data about the relative number of active devices that support a particular
+<p>This section provides data about the relative number of devices that support a particular
 version of OpenGL ES. Note that support for one particular version of OpenGL ES also implies
 support for any lower version (for example, support for version 2.0 also implies support for
 1.1).</p>
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A9.2,90.8&chf=bg,s,00000000" />
+src="//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A0.3,99.7&chf=bg,s,00000000" />
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -204,10 +112,6 @@
 &lt;supports-gl-texture&gt;}</a> element to declare the GL compression formats that your application
 uses.</p>
 
-<p class="note"><strong>Note:</strong> This data is based on the number
-of Android devices that have accessed Google Play within a 7-day period
-ending on the data collection date noted below.</p>
-
 
 <table style="width:350px">
 <tr>
@@ -216,14 +120,347 @@
 </tr>
 <tr>
 <td>1.1 only</th>
-<td>9.2%</td>
+<td>0.3%</td>
 </tr>
 <tr>
 <td>2.0 &amp; 1.1</th>
-<td>90.8%</td>
+<td>99.7%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on October 1, 2012</em></p>
+<p style="clear:both"><em>Data collected during a 14-day period ending on April 2, 2013</em></p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+<script>
+var VERSION_DATA =
+[
+  {
+    "chart": "//chart.googleapis.com/chart?chf=bg%2Cs%2C00000000&chd=t%3A1.8%2C4.0%2C39.8%2C0.2%2C29.3%2C25.0&chl=Eclair%7CFroyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean&chs=500x250&cht=p&chco=c4df9b%2C6fad0c",
+    "data": [
+      {
+        "api": 4,
+        "name": "Donut",
+        "perc": "0.1"
+      },
+      {
+        "api": 7,
+        "name": "Eclair",
+        "perc": "1.7"
+      },
+      {
+        "api": 8,
+        "name": "Froyo",
+        "perc": "4.0"
+      },
+      {
+        "api": 9,
+        "name": "Gingerbread",
+        "perc": "0.1"
+      },
+      {
+        "api": 10,
+        "name": "Gingerbread",
+        "perc": "39.7"
+      },
+      {
+        "api": 13,
+        "name": "Honeycomb",
+        "perc": "0.2"
+      },
+      {
+        "api": 15,
+        "name": "Ice Cream Sandwich",
+        "perc": "29.3"
+      },
+      {
+        "api": 16,
+        "name": "Jelly Bean",
+        "perc": "23.0"
+      },
+      {
+        "api": 17,
+        "name": "Jelly Bean",
+        "perc": "2.0"
+      }
+    ]
+  }
+];
+
+
+
+
+
+var SCREEN_DATA =
+[
+  {
+    "data": {
+      "Large": {
+        "hdpi": "0.5",
+        "ldpi": "0.7",
+        "mdpi": "2.7",
+        "tvdpi": "1.0",
+        "xhdpi": "0.8"
+      },
+      "Normal": {
+        "hdpi": "37.9",
+        "ldpi": "0.1",
+        "mdpi": "16.1",
+        "xhdpi": "25.0",
+        "xxhdpi": "0.8"
+      },
+      "Small": {
+        "ldpi": "9.5"
+      },
+      "Xlarge": {
+        "hdpi": "0.1",
+        "ldpi": "0.1",
+        "mdpi": "4.6",
+        "xhdpi": "0.1"
+      }
+    },
+    "densitychart": "//chart.googleapis.com/chart?chf=bg%2Cs%2C00000000&chd=t%3A10.4%2C23.4%2C1.0%2C38.5%2C25.9%2C0.8&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chs=400x250&cht=p&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?chf=bg%2Cs%2C00000000&chd=t%3A4.9%2C5.7%2C79.9%2C9.5&chl=Xlarge%7CLarge%7CNormal%7CSmall&chs=400x250&cht=p&chco=c4df9b%2C6fad0c"
+  }
+];
+
+
+
+var VERSION_NAMES =
+[
+  {"api":0},{"api":1},{"api":2},{"api":3},
+  { 
+    "api":4,
+    "link":"<a href='/about/versions/android-1.6.html'>1.6</a>",
+    "codename":"Donut",
+  },
+  { "api":5},
+  { "api":6},
+  { 
+    "api":7,
+    "link":"<a href='/about/versions/android-2.1.html'>2.1</a>",
+    "codename":"Eclair",
+  },
+  {
+    "api":8,
+    "link":"<a href='/about/versions/android-2.2.html'>2.2</a>",
+    "codename":"Froyo"
+  },
+  {
+    "api":9,
+    "link":"<a href='/about/versions/android-2.3.html'>2.3 -<br>2.3.2</a>",
+    "codename":"Gingerbread"
+  },
+  {
+    "api":10,
+    "link":"<a href='/about/versions/android-2.3.3.html'>2.3.3 -<br>2.3.7</a>",
+    "codename":"Gingerbread"
+  },
+  { "api":11},
+  {
+    "api":12,
+    "link":"<a href='/about/versions/android-3.1.html'>3.1</a>",
+    "codename":"Honeycomb"
+  },
+  {
+    "api":13,
+    "link":"<a href='/about/versions/android-3.2.html'>3.2</a>",
+    "codename":"Honeycomb"
+  },
+  { "api":14},
+  {
+    "api":15,
+    "link":"<a href='/about/versions/android-4.0.html'>4.0.3 -<br>4.0.4</a>",
+    "codename":"Ice Cream Sandwich"
+  },
+  {
+    "api":16,
+    "link":"<a href='/about/versions/android-4.1.html'>4.1.x</a>",
+    "codename":"Jelly Bean"
+  },
+  {
+    "api":17,
+    "link":"<a href='/about/versions/android-4.2.html'>4.2.x</a>",
+    "codename":"Jelly Bean"
+  }
+];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+$(document).ready(function(){
+  // for each set of data (each month)
+  $.each(VERSION_DATA, function(i, set) {
+
+    // set up wrapper divs
+    var $div = $('<div class="chart"'
+         + ((i == 0) ? ' style="display:block"' : '')
+         + ' >');
+    var $divtable = $('<div class="col-5" style="margin-left:0">');
+    var $divchart = $('<div class="col-8" style="margin-right:0">');
+
+    // set up a new table
+    var $table = $("<table>");
+    var $trh = $("<tr><th>Version</th>"
+                   + "<th>Codename</th>"
+                   + "<th>API</th>"
+                   + "<th>Distribution</th></tr>");
+    $table.append($trh);
+
+    // loop each data set (each api level represented in stats)
+    $.each(set.data, function(i, data) {
+      // check if we need to rowspan the codename
+      var rowspan = 1;
+      // must not be first row
+      if (i > 0) {
+        // if this row's codename is the same as previous row codename
+        if (data.name == set.data[i-1].name) {
+          rowspan = 0;
+        // otherwise, as long as this is not the last row
+        } else if (i < (set.data.length - 1)) {
+          // increment rowspan for each subsequent row w/ same codename
+          while (data.name == set.data[i+rowspan].name) {
+            rowspan++;
+            // unless we've reached the last row
+            if ((i + rowspan) >= set.data.length) break;
+          }
+        }
+      }
+
+      // create table row and get corresponding version info from VERSION_NAMES
+      var $tr = $("<tr>");
+      $tr.append("<td>" + VERSION_NAMES[data.api].link + "</td>");
+      if (rowspan > 0) {
+        $tr.append("<td rowspan='" + rowspan + "'>" + VERSION_NAMES[data.api].codename + "</td>");
+      }
+      $tr.append("<td>" + data.api + "</td>");
+      $tr.append("<td>" + data.perc + "%</td>");
+      $table.append($tr);
+    });
+
+    // create chart image
+    var $chart = $('<img style="margin-left:30px" alt="" src="' + set.chart + '" />');
+
+    // stack up and insert the elements
+    $divtable.append($table);
+    $divchart.append($chart);
+    $div.append($divtable).append($divchart);
+    $("#version-chart").append($div);
+  });
+
+
+
+  var SCREEN_SIZES = ["Small","Normal","Large","Xlarge"];
+  var SCREEN_DENSITIES = ["ldpi","mdpi","tvdpi","hdpi","xhdpi","xxhdpi"];
+
+
+  // for each set of screens data (each month)
+  $.each(SCREEN_DATA, function(i, set) {
+
+    // set up wrapper divs
+    var $div = $('<div class="screens-chart"'
+         + ((i == 0) ? ' style="display:block"' : '')
+         + ' >');
+
+    // set up a new table
+    var $table = $("<table>");
+    var $trh = $("<tr><th></th></tr>");
+    $.each(SCREEN_DENSITIES, function(i, density) {
+      $trh.append("<th scope='col'>" + density + "</th>");
+    });
+    $trh.append("<th scope='col' class='total'>Total</th>");
+    $table.append($trh);
+
+    // array to hold totals for each density
+    var densityTotals = new Array(SCREEN_DENSITIES.length);
+    $.each(densityTotals, function(i, total) {
+      densityTotals[i] = 0; // make them all zero to start
+    });
+
+    // loop through each screen size
+    $.each(SCREEN_SIZES, function(i, size) {
+      // if there are any devices of this size
+      if (typeof set.data[size] != "undefined") {
+        // create table row and insert data
+        var $tr = $("<tr>");
+        $tr.append("<th scope='row'>" + size + "</th>");
+        // variable to sum all densities for this size
+        var total = 0;
+        // loop through each density
+        $.each(SCREEN_DENSITIES, function(i, density) {
+          var num = typeof set.data[size][density] != "undefined" ? set.data[size][density] : 0;
+          $tr.append("<td>" + (num != 0 ? num + "%" : "") + "</td>");
+          total += parseFloat(num);
+          densityTotals[i] += parseFloat(num);
+        })
+        $tr.append("<td class='total'>" + total.toFixed(1) + "%</td>");
+        $table.append($tr);
+      }
+    });
+
+    // create row of totals for each density
+    var $tr = $("<tr><th class='total'>Total</th></tr>");
+    $.each(densityTotals, function(i, total) {
+      $tr.append("<td class='total'>" + total.toFixed(1) + "%</td>");
+    });
+    $table.append($tr);
+
+    // create charts
+    var $sizechart = $('<img style="float:left;width:380px" alt="" src="'
+            + set.layoutchart + '" />');
+    var $densitychart = $('<img style="float:left;width:380px" alt="" src="'
+            + set.densitychart + '" />');
+
+    // stack up and insert the elements
+    $div.append($table).append($sizechart).append($densitychart);
+    $("#screens-chart").append($div);
+  });
+
+
+});
+
+
+
+function changeVersionDate() {
+  var date = $('#date-versions option:selected').val();
+
+  $(".chart").hide();
+  $(".chart."+date+"").show();
+}
+
+
+function changeScreensVersionDate() {
+  var date = $('#date-screens option:selected').val();
+
+  $(".screens-chart").hide();
+  $(".screens-chart."+date+"").show();
+}
+
+</script>
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index f2fd0c4..868227a 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -122,7 +122,7 @@
 receiving the app uses it to invite the specified contact to that
 social network. Most apps will be on the receiving-end of this operation. For example, the
 built-in People app invokes the invite intent when the user selects "Add connection" for a specific
-social app that's listed in a person's contact details.</p> 
+social app that's listed in a person's contact details.</p>
 
 <p>To make your app visible as in the "Add connection" list, your app must provide a sync adapter to
 sync contact information from your social network. You must then indicate to the system that your
@@ -327,7 +327,7 @@
 function). You may provide multiple mipmap levels. If the output texture has not been bound to a
 texture image, it will be automatically bound by the effect as a {@link
 android.opengl.GLES20#GL_TEXTURE_2D} and with one mipmap level (0), which will have the same
-size as the input.</p> 
+size as the input.</p>
 
 <p>All effects listed in {@link android.media.effect.EffectFactory} are guaranteed to be supported.
 However, some additional effects available from external libraries are not supported by all devices,
@@ -452,7 +452,7 @@
 value is greater than zero. Also, some devices may not support identification of eyes and mouth,
 in which case, those fields in the {@link android.hardware.Camera.Face} object will be null.</p>
 
-  
+
 <h4>Focus and metering areas</h4>
 
 <p>Camera apps can now control the areas that the camera uses for focus and for metering white
@@ -495,7 +495,7 @@
 
 <h4>Other camera features</h4>
 
-<ul>  
+<ul>
 <li>While recording video, you can now call {@link android.hardware.Camera#takePicture
 takePicture()} to save a photo without interrupting the video session. Before doing so, you should
 call {@link android.hardware.Camera.Parameters#isVideoSnapshotSupported} to be sure the hardware
@@ -775,7 +775,7 @@
   <li>When invoked, the {@link
 android.view.View#sendAccessibilityEvent sendAccessibilityEvent()} and {@link
 android.view.View#sendAccessibilityEventUnchecked sendAccessibilityEventUnchecked()} methods defer
-to {@link android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()}. 
+to {@link android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()}.
   <p>Custom implementations of {@link android.view.View} might want to implement {@link
 android.view.View#onInitializeAccessibilityEvent onInitializeAccessibilityEvent()} to
 attach additional accessibility information to the {@link
@@ -1022,46 +1022,6 @@
 
 
 
-<h3 id="RenderScript">RenderScript</h3>
-
-<p>Three major features have been added to RenderScript:</p>
-
-<ul>
-  <li>Off-screen rendering to a framebuffer object</li>
-  <li>Rendering inside a view</li>
-  <li>RS for each from the framework APIs</li>
-</ul>
-
-<p>The {@link android.renderscript.Allocation} class now supports a {@link
-android.renderscript.Allocation#USAGE_GRAPHICS_RENDER_TARGET} memory space, which allows you to
-render things directly into the {@link android.renderscript.Allocation} and use it as a framebuffer
-object.</p>
-
-<p>{@link android.renderscript.RSTextureView} provides a means to display RenderScript graphics
-inside of a {@link android.view.View},  unlike {@link android.renderscript.RSSurfaceView}, which
-creates a separate window. This key difference allows you to do things such as move, transform, or
-animate an {@link android.renderscript.RSTextureView} as well as draw RenderScript graphics inside
-a view that lies within an activity layout.</p>
-
-<p>The {@link android.renderscript.Script#forEach Script.forEach()} method allows you to call
-RenderScript compute scripts from the VM level and have them automatically delegated to available
-cores on the device. You do not use this method directly, but any compute RenderScript that you
-write will have a {@link android.renderscript.Script#forEach forEach()}  method that you can call in
-the reflected RenderScript class. You can call the reflected {@link
-android.renderscript.Script#forEach forEach()} method by passing in an input {@link
-android.renderscript.Allocation} to process, an output {@link android.renderscript.Allocation} to
-write the result to, and a {@link android.renderscript.FieldPacker} data structure in case the
-RenderScript needs more information. Only one of the {@link android.renderscript.Allocation}s is
-necessary and the data structure is optional.</p>
-
-
-
-
-
-
-
-
-
 <h3 id="Enterprise">Enterprise</h3>
 
 <p>Android 4.0 expands the capabilities for enterprise application with the following features.</p>
@@ -1758,7 +1718,7 @@
 notes for more information.</li>
     </ul>
   </dd>
-  
+
   <dt><a href="android-3.1.html">Android 3.1</a></dt>
   <dd>
     <ul>
@@ -1781,7 +1741,7 @@
 notes for many more new APIs.</li>
     </ul>
   </dd>
-  
+
   <dt><a href="android-3.2.html">Android 3.2</a></dt>
   <dd>
     <ul>
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index acb2538..71957be 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -904,7 +904,7 @@
 
 <h3>Media codec access</h3>
 
-<p>Android 4.1 provides low-level access to platform hardware and software codecs. Apps can query the system to discover what <strong>low-level media codecs</strong> are available on the device and then and use them in the ways they need. For example, you can now create multiple instances of a media codec, queue input buffers, and receive output buffers in return. In addition, the media codec framework supports protected content. Apps can query for an available codec that is able to play protected content with a DRM solution available on the the device.</p>
+<p>Android 4.1 provides low-level access to platform hardware and software codecs. Apps can query the system to discover what <strong>low-level media codecs</strong> are available on the device and then and use them in the ways they need. For example, you can now create multiple instances of a media codec, queue input buffers, and receive output buffers in return. In addition, the media codec framework supports protected content. Apps can query for an available codec that is able to play protected content with a DRM solution available on the device.</p>
 
 <h3>USB Audio</h3>
 
diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd
index 82e2477..9e82ed4 100644
--- a/docs/html/design/building-blocks/buttons.jd
+++ b/docs/html/design/building-blocks/buttons.jd
@@ -1,4 +1,5 @@
 page.title=Buttons
+page.tags="button"
 @jd:body
 
 <p>A button consists of text and/or an image that clearly communicates what action will occur when the
diff --git a/docs/html/design/building-blocks/dialogs.jd b/docs/html/design/building-blocks/dialogs.jd
index a2ece2e..2f6ca27 100644
--- a/docs/html/design/building-blocks/dialogs.jd
+++ b/docs/html/design/building-blocks/dialogs.jd
@@ -1,4 +1,5 @@
 page.title=Dialogs
+page.tags="dialog","alert","popup","toast"
 @jd:body
 
 <p>Dialogs prompt the user for decisions or additional information required by the app to continue a
diff --git a/docs/html/design/building-blocks/grid-lists.jd b/docs/html/design/building-blocks/grid-lists.jd
index 775ebcc..69a43b1 100644
--- a/docs/html/design/building-blocks/grid-lists.jd
+++ b/docs/html/design/building-blocks/grid-lists.jd
@@ -1,4 +1,5 @@
 page.title=Grid Lists
+page.tags="gridview","layout"
 @jd:body
 
 <img src="{@docRoot}design/media/gridview_overview.png">
diff --git a/docs/html/design/building-blocks/lists.jd b/docs/html/design/building-blocks/lists.jd
index aaa86b8..16927a6 100644
--- a/docs/html/design/building-blocks/lists.jd
+++ b/docs/html/design/building-blocks/lists.jd
@@ -1,4 +1,5 @@
 page.title=Lists
+page.tags="listview","layout"
 @jd:body
 
 <p>Lists present multiple line items in a vertical arrangement. They can be used for data selection as
diff --git a/docs/html/design/building-blocks/pickers.jd b/docs/html/design/building-blocks/pickers.jd
index b328df9..47363d0 100644
--- a/docs/html/design/building-blocks/pickers.jd
+++ b/docs/html/design/building-blocks/pickers.jd
@@ -1,4 +1,5 @@
 page.title=Pickers
+page.tags="datepicker","timepicker"
 @jd:body
 
 <p>Pickers provide a simple way to select a single value from a set. In addition to touching the
diff --git a/docs/html/design/building-blocks/progress.jd b/docs/html/design/building-blocks/progress.jd
index 7342387..96cc1af 100644
--- a/docs/html/design/building-blocks/progress.jd
+++ b/docs/html/design/building-blocks/progress.jd
@@ -1,4 +1,5 @@
 page.title=Progress &amp; Activity
+page.tags="progressbar"
 @jd:body
 
 <p>Progress bars and activity indicators signal to users that something is happening that will take a moment.</p>
diff --git a/docs/html/design/building-blocks/scrolling.jd b/docs/html/design/building-blocks/scrolling.jd
index 7695157..66999f9 100644
--- a/docs/html/design/building-blocks/scrolling.jd
+++ b/docs/html/design/building-blocks/scrolling.jd
@@ -1,4 +1,5 @@
 page.title=Scrolling
+page.tags="scrollview","listview"
 @jd:body
 
 <p>Scrolling allows the user to navigate to content in the overflow using a swipe gesture. The
diff --git a/docs/html/design/building-blocks/seek-bars.jd b/docs/html/design/building-blocks/seek-bars.jd
index 3407ddd..9d38e36 100644
--- a/docs/html/design/building-blocks/seek-bars.jd
+++ b/docs/html/design/building-blocks/seek-bars.jd
@@ -1,4 +1,5 @@
 page.title=Seek Bars and Sliders
+page.tags="seekbar","progressbar"
 @jd:body
 
 <p>Interactive sliders make it possible to select a value from a continuous or discrete range of values
diff --git a/docs/html/design/building-blocks/spinners.jd b/docs/html/design/building-blocks/spinners.jd
index 279565f..8c80b91 100644
--- a/docs/html/design/building-blocks/spinners.jd
+++ b/docs/html/design/building-blocks/spinners.jd
@@ -1,4 +1,5 @@
 page.title=Spinners
+page.tags="spinner","drop down"
 @jd:body
 
 <p>Spinners provide a quick way to select one value from a set. In the default state, a spinner shows
diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd
index d9cfd07..6386bdf 100644
--- a/docs/html/design/building-blocks/switches.jd
+++ b/docs/html/design/building-blocks/switches.jd
@@ -1,4 +1,5 @@
 page.title=Switches
+page.tags="switch","checkbox","radiobutton"
 @jd:body
 
 <p>Switches allow the user to select options. There are three kinds of switches: checkboxes, radio
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 0a0f907..1fe2c62 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -1,4 +1,5 @@
 page.title=Tabs
+page.tags="tabs","action bar","navigation"
 @jd:body
 
 <img src="{@docRoot}design/media/tabs_overview.png">
diff --git a/docs/html/design/building-blocks/text-fields.jd b/docs/html/design/building-blocks/text-fields.jd
index 563f247..c1bed78 100644
--- a/docs/html/design/building-blocks/text-fields.jd
+++ b/docs/html/design/building-blocks/text-fields.jd
@@ -1,4 +1,5 @@
 page.title=Text Fields
+page.tags="text","edittext","input",
 @jd:body
 
 <p>Text fields allow the user to type text into your app. They can be either single line or multi-line.
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
index 2c3333f..edf3843 100644
--- a/docs/html/design/patterns/accessibility.jd
+++ b/docs/html/design/patterns/accessibility.jd
@@ -1,4 +1,5 @@
 page.title=Accessibility
+page.tags="accessibility","navigation"
 @jd:body
 
 <p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 265ccde..da9c3c3 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -1,4 +1,5 @@
 page.title=Action Bar
+page.tags="actionbar","navigation"
 @jd:body
 
 <img src="{@docRoot}design/media/action_bar_pattern_overview.png">
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index 04af57b..e1bb819 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -1,4 +1,5 @@
 page.title=Application Structure
+page.tags="navigation","layout"
 @jd:body
 
 <p>Apps come in many varieties that address very different needs. For example:</p>
diff --git a/docs/html/design/patterns/confirming-acknowledging.jd b/docs/html/design/patterns/confirming-acknowledging.jd
index ce0631b..f2e88ec 100644
--- a/docs/html/design/patterns/confirming-acknowledging.jd
+++ b/docs/html/design/patterns/confirming-acknowledging.jd
@@ -1,4 +1,5 @@
 page.title=Confirming &amp; Acknowledging
+page.tags="dialog","toast"
 @jd:body
 
 <p>In some situations, when a user invokes an action in your app, it's a good idea to <em>confirm</em> or <em>acknowledge</em> that action through text.</p>
diff --git a/docs/html/design/patterns/gestures.jd b/docs/html/design/patterns/gestures.jd
index e579cee..3ef133d 100644
--- a/docs/html/design/patterns/gestures.jd
+++ b/docs/html/design/patterns/gestures.jd
@@ -1,4 +1,5 @@
 page.title=Gestures
+page.tags="gesture","input"
 @jd:body
 
 <p>Gestures allow users to interact with your app by manipulating the screen objects you provide. The
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index e607676..cbf29cb 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,4 +1,5 @@
 page.title=Multi-pane Layouts
+page.tags="tablet","navigation","layout","fragment"
 @jd:body
 
 <p>When writing an app for Android, keep in mind that Android devices come in many different screen
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 656e6e5..36debbe 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,4 +1,5 @@
 page.title=Navigation with Back and Up
+page.tags="navigation","activity"
 @jd:body
 
 <p>Consistent navigation is an essential component of the overall user experience. Few things frustrate
diff --git a/docs/html/design/patterns/notifications.jd b/docs/html/design/patterns/notifications.jd
index 0665774..3ae827e 100644
--- a/docs/html/design/patterns/notifications.jd
+++ b/docs/html/design/patterns/notifications.jd
@@ -1,4 +1,5 @@
 page.title=Notifications
+page.tags="notification"
 @jd:body
 
 <p>The notification system allows your app to keep the user informed about events, such as new chat messages or a calendar event. Think of notifications as a news channel that alerts the user to important events as they happen or a log that chronicles events while the user is not paying attention.</p>
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index e9d22e6..682ce56 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -1,4 +1,5 @@
 page.title=Selection
+page.tags="actionmode","navigation"
 @jd:body
 
 <p>Android 3.0 changed the <em>long press</em> gesture&mdash;that is, a touch that's held in the same position for a moment&mdash;to be the global gesture to select data.. This affects the way you should
diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
index fef7585..f86cd39 100644
--- a/docs/html/design/patterns/settings.jd
+++ b/docs/html/design/patterns/settings.jd
@@ -1,4 +1,5 @@
 page.title=Settings
+page.tags="settings","preferences"
 @jd:body
 
 <p>Settings is a place in your app where users indicate their preferences for how your app should
diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
index daddd31..b86d990 100644
--- a/docs/html/design/patterns/swipe-views.jd
+++ b/docs/html/design/patterns/swipe-views.jd
@@ -1,4 +1,5 @@
 page.title=Swipe Views
+page.tags="viewpager","navigation"
 @jd:body
 
 <p>Efficient navigation is one of the cornerstones of a well-designed app. While apps are generally
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 54726b1..f2b0f4a 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,4 +1,5 @@
 page.title=Widgets
+page.tags="appwidget"
 @jd:body
 
 <p>Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
@@ -15,7 +16,7 @@
 <div class="layout-content-row">
   <div class="layout-content-col span-6">
     <h3>Collection widgets</h3>
-    <p>As the name implies, collection widgets specialize on displaying multitude elements of the same type, such as a collection of pictures from a gallery app, a collection of articles from a news app or a collection of emails/messages from a communication app. Collection widgets typically focus on two use cases: browsing the collection, and opening an element of the collection to its detail view for consumption. Collection widgets can scroll vertically.</p>
+    <p>As the name implies, collection widgets specialize in displaying multitude elements of the same type, such as a collection of pictures from a gallery app, a collection of articles from a news app or a collection of emails/messages from a communication app. Collection widgets typically focus on two use cases: browsing the collection, and opening an element of the collection to its detail view for consumption. Collection widgets can scroll vertically.</p>
   </div>
   <div class="layout-content-col span-3">
     <img src="{@docRoot}design/media/widgets_collection_gmail.png">
@@ -136,4 +137,4 @@
   <li>Choose the right widget type for your purpose.</li>
   <li>For resizable widgets, plan how the content for your widget should adapt to different sizes.</li>
   <li>Make your widget orientation and device independent by ensuring that the layout is capable of stretching and contracting.</li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index 190a6d9..0cb2635 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -345,7 +345,7 @@
   var playlistId = "PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0"; /* DevBytes */
   var script = "<script type='text/javascript' src='//gdata.youtube.com/feeds/api/playlists/"
                 + playlistId +
-                "?v=2&alt=json-in-script&max-results=10&callback=renderDevelopersLivePlaylist&orderby=published'><\/script > ";
+                "?v=2&alt=json-in-script&max-results=10&callback=renderDevelopersLivePlaylist&orderby=reversedPosition'><\/script > ";
   $("body").append(script);
 }
 
diff --git a/docs/html/distribute/googleplay/about/visibility.jd b/docs/html/distribute/googleplay/about/visibility.jd
index 4957c0f..18f60e9 100644
--- a/docs/html/distribute/googleplay/about/visibility.jd
+++ b/docs/html/distribute/googleplay/about/visibility.jd
@@ -39,7 +39,7 @@
 </div>
 
 <div>
-<p>Google Play is also a top destination for visitors from the the web. Anyone
+<p>Google Play is also a top destination for visitors from the web. Anyone
 with a browser can explore everything that Google Play has to offer from its <a
 href="http://play.google.com/store">web site</a>. Android users can even buy and
 install the apps they want and Google Play pushes them automatically to their
@@ -159,7 +159,7 @@
 
 <h4>Featured and Staff Picks</h4>
 
-<p>Each week the the Google Play editorial staff selects a new set of apps to
+<p>Each week the Google Play editorial staff selects a new set of apps to
 promote in its popular <em>Featured</em> and <em>Staff Picks</em> collections.
 </p>
 
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 09ce95e..089baf5 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -149,7 +149,16 @@
 it to the 3rd-party application server, which uses it to identify each device 
 that has registered to receive messages for a given Android application. In other words,
 a registration ID is tied to a particular Android application running on a particular
-device.</td>
+device.
+<br/>
+<br/>
+<strong>Note:</strong> If you use 
+<a href="https://developer.android.com/google/backup/index.html">backup and restore</a>,
+you should explicitly avoid backing up registration IDs. When you back up
+a device, apps back up shared prefs indiscriminately. If you don't explicitly
+exclude the GCM registration ID, it could get reused on a new device,
+which would cause delivery errors.
+</td>
   </tr>
   <tr>
     <td><strong>Google User Account</strong></td>
@@ -295,6 +304,13 @@
   </li>
 </ul>
 
+<p class="note"><strong>Note:</strong> This section describes how to
+write an app without using the 
+<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>. 
+For details on writing
+an app that uses the helper libraries (which is the recommended and
+simpler approach), see <a href="gs.html">GCM: Getting Started</a>.
+
 <h3 id="manifest">Creating the Manifest</h3>
 
 <p>Every Android application must have an <code>AndroidManifest.xml</code> file (with
@@ -585,6 +601,7 @@
 could not run properly. </li>
 </ul>
 
+
 <h2 id="server">Role of the 3rd-party Application Server</h2>
 
 <p>Before you can write client Android applications that use the GCM feature, you must
@@ -758,9 +775,15 @@
   <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
   </pre>
 
-  <p class="note"><strong>Note:</strong> If your organization has a firewall that restricts the traffic to or from the Internet, you'll need to configure it to allow connectivity with GCM. The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but it sometimes uses 5229 and 5230.
-GCM doesn't provide specific IPs. It changes IPs frequently. We recommend against using ACLs but if you must use them, take a broad approach such as the method suggested in <a href="http://support.google.com/code/bin/answer.py?hl=en&answer=62464">this support link</a>.
-</p>
+<p class="note"><strong>Note:</strong> If your organization has a firewall 
+that restricts the traffic to or 
+from the Internet, you need to configure it to allow connectivity with GCM in order for
+your Android devices to receive messages. 
+The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but 
+it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should 
+allow your firewall to accept incoming connections from all IP addresses 
+contained in the IP blocks listed in Google's ASN of 15169.</p>
+
 
 <h4 id="response">Response format</h4>
 
@@ -770,7 +793,7 @@
   <li>The GCM server rejects the request.</li>
 </ul>
 
-<p>When the messge is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected, 
+<p>When the message is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected, 
 the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
 
 <p>The following table summarizes the statuses that the HTTP response header might contain. Click the troubleshoot link for advice on how to deal with each type of error.</p>
@@ -825,7 +848,7 @@
     <td>Array of objects representing the status of the messages processed. The objects are listed in the same order as the request (i.e., for each registration ID in the request, its result is listed in the same index in the response) and they can have these fields:<br>
       <ul>
         <li><code>message_id</code>: String representing the message when it was successfully processed.</li>
-        <li><code>registration_id</code>: If set,  means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.<br />
+        <li><code>registration_id</code>: If set,  means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.
         </li>
         <li><code>error</code>: String describing an error that occurred while processing the message for that recipient. The possible values are the same as documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers were busy and could not process the message for that  particular recipient, so it could be retried).</li>
     </ul></td>
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index 37ef684..5d34641 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -86,8 +86,15 @@
 
 <h2 id="libs">Install the Helper Libraries</h2>
 <p>To perform the steps described in the following sections, you must first install the 
-<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>. 
-From the SDK Manager, install <strong>Extras &gt; Google Cloud Messaging for Android Library</strong>. This creates a <code>gcm</code> directory under <code><em>YOUR_SDK_ROOT</em>/extras/google/</code> containing these subdirectories: <code>gcm-client</code>, <code>gcm-server</code>, <code>samples/gcm-demo-client</code>, <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
+<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>. Note that while using the helper libraries is recommended, it is not required. See the <a href="gcm.html#writing_apps">GCM Architectural Overview</a> for a description of how to write apps without using the helper libraries.
+
+<p>To install the helper libraries, choose 
+<strong>Extras &gt; Google Cloud Messaging for Android Library</strong>
+from the SDK Manager. This creates a <code>gcm</code> directory under
+<code><em>YOUR_SDK_ROOT</em>/extras/google/</code> containing these
+subdirectories: <code>gcm-client</code>, <code>gcm-server</code>,
+<code>samples/gcm-demo-client</code>, <code>samples/gcm-demo-server</code>,
+and <code>samples/gcm-demo-appengine</code>.</p>
 
 <p class="note"><strong>Note:</strong> If you don't see <strong>Extras &gt; Google Cloud Messaging for Android Library</strong> in the SDK Manager, make sure you are running version 20 or higher. Be sure to restart the SDK Manager after updating it.</p>
 
diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
index 3365cfc..57227a8 100644
--- a/docs/html/google/play/billing/billing_integrate.jd
+++ b/docs/html/google/play/billing/billing_integrate.jd
@@ -19,6 +19,7 @@
        <li><a href="#Subs">Implementing Subscriptions</a><li>
        </ol>
     </li>
+    <li><a href="#billing-security">Securing Your App</a>
   </ol>
   <h2>Reference</h2>
   <ol>
@@ -361,6 +362,34 @@
 the user. Once a subscription expires without renewal, it will no longer appear 
 in the returned {@code Bundle}.</p>
 
+<h2 id="billing-security">Securing Your Application</h2>
+
+<p>To help ensure the integrity of the transaction information that is sent to 
+your application, Google Play signs the JSON string that contains the response 
+data for a purchase order. Google Play uses the private key that is associated 
+with your application in the Developer Console to create this signature. The 
+Developer Console generates an RSA key pair for each application.<p>
+
+<p class="note"><strong>Note:</strong>To find the public key portion of this key 
+pair, open your application's details in the Developer Console, then click on 
+<strong>Services & APIs</strong>, and look at the field titled 
+<strong>Your License Key for This Application</strong>.</p>
+
+<p>The Base64-encoded RSA public key generated by Google Play is in binary 
+encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public 
+key that is used with Google Play licensing.</p>
+
+<p>When your application receives this signed response you can 
+use the public key portion of your RSA key pair to verify the signature. 
+By performing signature verification you can detect responses that have 
+been tampered with or that have been spoofed. You can perform this signature 
+verification step in your application; however, if your application connects 
+to a secure remote server then we recommend that you perform the signature 
+verification on that server.</p>
+
+<p>For more information about best practices for security and design, see <a
+href="{@docRoot}google/play/billing/billing_best_practices.html">Security and Design</a>.</p>
+
 
 
 
diff --git a/docs/html/google/play/billing/billing_reference.jd b/docs/html/google/play/billing/billing_reference.jd
index 1410e65..e168d70 100644
--- a/docs/html/google/play/billing/billing_reference.jd
+++ b/docs/html/google/play/billing/billing_reference.jd
@@ -143,7 +143,9 @@
   </tr>
   <tr>
     <td>{@code INAPP_DATA_SIGNATURE}</td>
-    <td>String containing the signature of the purchase data that was signed with the private key of the developer.</td>
+    <td>String containing the signature of the purchase data that was signed 
+with the private key of the developer. The data signature uses the 
+RSASSA-PKCS1-v1_5 scheme.</td>
   </tr>
 </table>
 </p>
diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd
old mode 100755
new mode 100644
diff --git a/docs/html/google/play/licensing/adding-licensing.jd b/docs/html/google/play/licensing/adding-licensing.jd
index f991e14..93561f6 100644
--- a/docs/html/google/play/licensing/adding-licensing.jd
+++ b/docs/html/google/play/licensing/adding-licensing.jd
@@ -598,15 +598,15 @@
 <p>First, open the class file of the application's main Activity and import
 {@code LicenseChecker} and {@code LicenseCheckerCallback} from the LVL package.</p>
 
-<pre>    import com.android.vending.licensing.LicenseChecker;
-    import com.android.vending.licensing.LicenseCheckerCallback;</pre>
+<pre>    import com.google.android.vending.licensing.LicenseChecker;
+    import com.google.android.vending.licensing.LicenseCheckerCallback;</pre>
 
 <p>If you are using the default {@code Policy} implementation provided with the LVL,
 ServerManagedPolicy, import it also, together with the AESObfuscator. If you are
 using a custom {@code Policy} or {@code Obfuscator}, import those instead. </p>
 
-<pre>    import com.android.vending.licensing.ServerManagedPolicy;
-    import com.android.vending.licensing.AESObfuscator;</pre>
+<pre>    import com.google.android.vending.licensing.ServerManagedPolicy;
+    import com.google.android.vending.licensing.AESObfuscator;</pre>
 
 <h3 id="lc-impl">Implement LicenseCheckerCallback as a private inner class</h3>
 
@@ -853,37 +853,39 @@
 
 <h3 id="account-key">Embed your public key for licensing</h3>
 
-<p>For each publisher account, the Google Play service automatically
-generates a  2048-bit RSA public/private key pair that is used exclusively for
-licensing. The key pair is uniquely associated with the publisher account and is
-shared across all applications that are published through the account. Although
-associated with a publisher account, the key pair is <em>not</em> the same as
-the key that you use to sign your applications (or derived from it).</p>
+<p>For each application, the Google Play service automatically
+generates a  2048-bit RSA public/private key pair that is used for 
+licensing and in-app billing. The key pair is uniquely associated with the 
+application. Although associated with the application, the key pair is 
+<em>not</em> the same as the key that you use to sign your applications (or derived from it).</p>
 
 <p>The Google Play Developer Console exposes the public key for licensing to any
-developer signed in to the publisher account, but it keeps the private key
+developer signed in to the Developer Console, but it keeps the private key
 hidden from all users in a secure location. When an application requests a
 license check for an application published in your account, the licensing server
-signs the license response using the private key of your account's key pair.
+signs the license response using the private key of your application's key pair.
 When the LVL receives the response, it uses the public key provided by the
 application to verify the signature of the license response. </p>
 
-<p>To add licensing to an application, you must obtain your publisher account's
+<p>To add licensing to an application, you must obtain your application's
 public key for licensing and copy it into your application. Here's how to find
-your account's public key for licensing:</p>
+your application's public key for licensing:</p>
 
 <ol>
 <li>Go to the Google Play <a
 href="http://play.google.com/apps/publish">Developer Console</a> and sign in.
 Make sure that you sign in to the account from which the application you are
 licensing is published (or will be published). </li>
-<li>In the account home page, locate the "Edit profile" link and click it. </li>
-<li>In the Edit Profile page, locate the "Licensing" pane, shown below. Your
-public key for licensing is given in the "Public key" text box. </li>
+<li>In the application details page, locate the <strong>Services & APIs</strong> 
+link and click it. </li>
+<li>In the <strong>Services & APIs</strong> page, locate the 
+<strong>Licensing & In-App Billing</strong> section. Your public key for 
+licensing is given in the 
+<strong>Your License Key For This Application</strong> field. </li>
 </ol>
 
 <p>To add the public key to your application, simply copy/paste the key string
-from the text box into your application as the value of the String variable
+from the field into your application as the value of the String variable
 <code>BASE64_PUBLIC_KEY</code>. When you are copying, make sure that you have
 selected the entire key string, without omitting any characters. </p>
 
@@ -965,16 +967,6 @@
 </ul>
 </div>
 
-
-
-
-
-
-
-
-
-
-
 <h2 id="app-obfuscation">Obfuscating Your Code</h2>
 
 <p>To ensure the security of your application, particularly for a paid
diff --git a/docs/html/google/play/licensing/index.jd b/docs/html/google/play/licensing/index.jd
index a13be10..6632fc0 100644
--- a/docs/html/google/play/licensing/index.jd
+++ b/docs/html/google/play/licensing/index.jd
@@ -16,7 +16,7 @@
 
 <p>The licensing service is a secure means of controlling access to your applications. When an
 application checks the licensing status, the Google Play server signs the licensing status
-response using a key pair that is uniquely associated with the publisher account. Your application
+response using a key pair that is uniquely associated with the application. Your application
 stores the public key in its compiled <code>.apk</code> file and uses it to verify the licensing
 status response.</p>
 
diff --git a/docs/html/google/play/licensing/licensing-reference.jd b/docs/html/google/play/licensing/licensing-reference.jd
index 4240097..7bfa61a 100644
--- a/docs/html/google/play/licensing/licensing-reference.jd
+++ b/docs/html/google/play/licensing/licensing-reference.jd
@@ -186,7 +186,7 @@
 </tr>
 <tr>
 <td>{@code ERROR_SERVER_FAILURE}</td>
-<td>Server error &mdash; the server could not load the publisher account's key
+<td>Server error &mdash; the server could not load the application's key
 pair for licensing.</td>
 <td>No</td>
 <td></td>
diff --git a/docs/html/google/play/licensing/overview.jd b/docs/html/google/play/licensing/overview.jd
index 2434a4c..4e1a9c9 100644
--- a/docs/html/google/play/licensing/overview.jd
+++ b/docs/html/google/play/licensing/overview.jd
@@ -38,13 +38,13 @@
 the result to your application, which can allow or disallow further use of the
 application as needed.</p>
 
-<p class="note"><strong>Note:</strong> If a paid application has been uploaded to Google Play but
-saved only as a draft application (the app is unpublished), the licensing server considers all users
-to be licensed users of the application (because it's not even possible to purchase the app).
-This exception is necessary in order for you to perform testing of your licensing
+<p class="note"><strong>Note:</strong> If a paid application has been uploaded 
+to Google Play, but saved only as a draft application (the app is 
+unpublished), the licensing server considers all users to be licensed users of 
+the application (because it's not even possible to purchase the app). This 
+exception is necessary in order for you to perform testing of your licensing 
 implementation.</p>
 
-
 <div class="figure" style="width:469px">
 <img src="{@docRoot}images/licensing_arch.png" alt=""/>
 <p class="img-caption"><strong>Figure 1.</strong> Your application initiates a
@@ -102,10 +102,11 @@
 server and you.</p>
 
 <p>The licensing service generates a single licensing key pair for each
-publisher account and exposes the public key in your account's profile page. You must copy the
-public key from the web site and embed it in your application source code. The server retains the
-private key internally and uses it to sign license responses for the applications you
-publish with that account.</p>
+application and exposes the public key in your application's 
+<strong>Services & APIs</strong> page in the Developer Console. You must copy 
+the public key from the Developer Console and embed it in your application 
+source code. The server retains the private key internally and uses it to sign 
+license responses for the applications you publish with that account.</p>
 
 <p>When your application receives a signed response, it uses the embedded public
 key to verify the data. The use of public key cryptography in the licensing
@@ -221,7 +222,7 @@
 <p>Licensing lets you move to a license-based model that is enforceable on
 all devices that have access to Google Play. Access is not bound to the
 characteristics of the host device, but to your
-publisher account on Google Play (through the app's public key) and the
+application on Google Play (through the app's public key) and the
 licensing policy that you define. Your application can be installed and
 managed on any device on any storage, including SD card.</p>
 
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index 2897804..1cbaa79 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -1,4 +1,5 @@
 page.title=Activities
+page.tags="activity","intent"
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/components/fragments.jd b/docs/html/guide/components/fragments.jd
index 7747b31..32c9f99 100644
--- a/docs/html/guide/components/fragments.jd
+++ b/docs/html/guide/components/fragments.jd
@@ -172,7 +172,7 @@
 
 <p>Most applications should implement at least these three methods for every fragment, but there are
 several other callback methods you should also use to handle various stages of the
-fragment lifecycle. All the lifecycle callback methods are discussed more later, in the section
+fragment lifecycle. All the lifecycle callback methods are discussed in more detail in the section
 about <a href="#Lifecycle">Handling the Fragment Lifecycle</a>.</p>
 
 
diff --git a/docs/html/guide/components/fundamentals.jd b/docs/html/guide/components/fundamentals.jd
index 2c33a26..ce50022 100644
--- a/docs/html/guide/components/fundamentals.jd
+++ b/docs/html/guide/components/fundamentals.jd
@@ -345,7 +345,7 @@
 {@link android.content.BroadcastReceiver} objects) and registered with the system by calling
 {@link android.content.Context#registerReceiver registerReceiver()}.</p>
 
-<p>For more about how to structure the manifest file for your application, see the <a
+<p>For more about how to structure the manifest file for your application, see <a
 href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>
 documentation. </p>
 
diff --git a/docs/html/guide/components/tasks-and-back-stack.jd b/docs/html/guide/components/tasks-and-back-stack.jd
index ecaba8d..a21bf34 100644
--- a/docs/html/guide/components/tasks-and-back-stack.jd
+++ b/docs/html/guide/components/tasks-and-back-stack.jd
@@ -231,7 +231,7 @@
 &lt;activity&gt;}</a> manifest element and with flags in the intent that you pass to {@link
 android.app.Activity#startActivity startActivity()}.</p>
 
-<p>In this regard, the the principal <a
+<p>In this regard, the principal <a
 href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a>
 attributes you can use are:</p>
 
@@ -319,7 +319,7 @@
 routes the intent to that instance through a call to its {@link
 android.app.Activity#onNewIntent onNewIntent()} method, rather than creating a new instance of the
 activity. The activity can be instantiated multiple times, each instance can
-belong to different tasks, and one task can have multiple instances (but only if the the
+belong to different tasks, and one task can have multiple instances (but only if the
 activity at the top of the back stack is <em>not</em> an existing instance of the activity).
   <p>For example, suppose a task's back stack consists of root activity A with activities B, C,
 and D on top (the stack is A-B-C-D; D is on top). An intent arrives for an activity of type D.
diff --git a/docs/html/guide/practices/index.jd b/docs/html/guide/practices/index.jd
index 04a43c5..48a849a 100644
--- a/docs/html/guide/practices/index.jd
+++ b/docs/html/guide/practices/index.jd
@@ -19,7 +19,7 @@
     
     <a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">
       <h4>Say Goodbye to the Menu Button</h4>
-      <p>As Ice Cream Sandwich rolls out to more devices, it?s important that you begin to migrate
+      <p>As Ice Cream Sandwich rolls out to more devices, it's important that you begin to migrate
 your designs to the action bar in order to promote a consistent Android user experience.</p>
     </a>
     
@@ -49,4 +49,4 @@
   </div>
 
 
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd b/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd
index c12b789..9f835a7 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd
@@ -96,7 +96,7 @@
     </th>
   </tr>
   <tr>
-    <th style="background-color:#f3f3f3;font-weight:normal">
+    <th>
       Action Bar Icon Size
     </th>
     <td>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_dialog.jd b/docs/html/guide/practices/ui_guidelines/icon_design_dialog.jd
index e02cdfc..a2c1459 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_dialog.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_dialog.jd
@@ -51,36 +51,46 @@
 <p class="table-caption"><strong>Table 1.</strong> Summary of finished dialog
 icon dimensions for each of the three generalized screen densities.</p>
 
-  <table>
-    <tbody>
-    <tr>
-      <th style="background-color:#f3f3f3;font-weight:normal">
-        <nobr>Low density screen <em>(ldpi)</em></nobr>
-      </th>
-      <th style="background-color:#f3f3f3;font-weight:normal">
-        <nobr>Medium density screen <em>(mdpi)</em></nobr>
-      </th>
-      <th style="background-color:#f3f3f3;font-weight:normal">
-        <nobr>High density screen <em>(hdpi)</em><nobr>
-      </th>
-    </tr>
-
-    <tr>
-      <td>
-        24 x 24 px
-      </td>
-      <td>
-        32 x 32 px
-      </td>
-      <td>
-        48 x 48 px
-      </td>
-    </tr>
-
-    </tbody>
-  </table>
-
-
+<table>
+  <tbody>
+  <tr>
+    <th></th>
+    <th>
+      <code>ldpi</code> (120 dpi)<br>
+      <small style="font-weight: normal">(Low density screen)</small>
+    </th>
+    <th>
+      <code>mdpi</code> (160 dpi)<br>
+      <small style="font-weight: normal">(Medium density screen)</small>
+    </th>
+    <th>
+      <code>hdpi</code> (240 dpi)<br>
+      <small style="font-weight: normal">(High density screen)</small>
+    </th>
+    <th>
+      <code>xhdpi</code> (320 dpi)<br>
+      <small style="font-weight: normal">(Extra-high density screen)</small>
+    </th>
+  </tr>
+  <tr>
+    <th style="background-color:#f3f3f3;font-weight:normal">
+      Dialog Icon Size
+    </th>
+    <td>
+      24 x 24 px
+    </td>
+    <td>
+      32 x 32 px
+    </td>
+    <td>
+      48 x 48 px
+    </td>
+    <td>
+      64 x 64 px
+    </td>
+  </tr>
+  </tbody>
+</table>
 
 <p><strong>Final art must be exported as a transparent PNG file. Do not include
 a background color</strong>.</p>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd b/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
index 200c135..4ec56b1 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
@@ -213,7 +213,7 @@
     </th>
   </tr>
   <tr>
-    <th style="background-color:#f3f3f3;font-weight:normal">
+    <th>
       Launcher Icon Size
     </th>
     <td>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_list.jd b/docs/html/guide/practices/ui_guidelines/icon_design_list.jd
index 2fbce87..38ceb85 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_list.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_list.jd
@@ -53,36 +53,46 @@
 <p class="table-caption"><strong>Table 1.</strong> Summary of finished list view
 icon dimensions for each of the three generalized screen densities.</p>
 
-  <table>
-    <tbody>
-    <tr>
-      <th style="background-color:#f3f3f3;font-weight:normal">
-        <nobr>Low density screen <em>(ldpi)</em></nobr>
-      </th>
-      <th style="background-color:#f3f3f3;font-weight:normal">
-        <nobr>Medium density screen <em>(mdpi)</em></nobr>
-      </th>
-      <th style="background-color:#f3f3f3;font-weight:normal">
-        <nobr>High density screen <em>(hdpi)</em><nobr>
-      </th>
-    </tr>
-
-    <tr>
-      <td>
-        24 x 24 px
-      </td>
-      <td>
-        32 x 32 px
-      </td>
-      <td>
-        48 x 48 px
-      </td>
-    </tr>
-
-    </tbody>
-  </table>
-
-
+<table>
+  <tbody>
+  <tr>
+    <th></th>
+    <th>
+      <code>ldpi</code> (120 dpi)<br>
+      <small style="font-weight: normal">(Low density screen)</small>
+    </th>
+    <th>
+      <code>mdpi</code> (160 dpi)<br>
+      <small style="font-weight: normal">(Medium density screen)</small>
+    </th>
+    <th>
+      <code>hdpi</code> (240 dpi)<br>
+      <small style="font-weight: normal">(High density screen)</small>
+    </th>
+    <th>
+      <code>xhdpi</code> (320 dpi)<br>
+      <small style="font-weight: normal">(Extra-high density screen)</small>
+    </th>
+  </tr>
+  <tr>
+    <th style="background-color:#f3f3f3;font-weight:normal">
+      List View Icon Size
+    </th>
+    <td>
+      24 x 24 px
+    </td>
+    <td>
+      32 x 32 px
+    </td>
+    <td>
+      48 x 48 px
+    </td>
+    <td>
+      64 x 64 px
+    </td>
+  </tr>
+  </tbody>
+</table>
 
 <p><strong>Final art must be exported as a transparent PNG file. Do not include
 a background color</strong>.</p>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd b/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd
index 8c15777..4cd4db3 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd
@@ -155,7 +155,7 @@
     </th>
   </tr>
   <tr>
-    <th style="background-color:#f3f3f3;font-weight:normal">
+    <th>
       Status Bar Icon Size<br><small>(Android 3.0 and Later)</small>
     </th>
     <td>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index 4a325db..f917576 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -339,7 +339,7 @@
 </code> is a permission that a {@link android.app.admin.DeviceAdminReceiver} subclass must
 have, to ensure that only the system can interact with the receiver (no application can be granted this permission). This
 prevents other applications from abusing your device admin app.</li>
-<li><code>android.app.action.DEVICE_ADMIN_ENABLED</code> is the  the primary
+<li><code>android.app.action.DEVICE_ADMIN_ENABLED</code> is the primary
 action that a {@link android.app.admin.DeviceAdminReceiver} subclass must handle to be
 allowed to manage a device. This is set to the receiver when the user enables
 the device admin app. Your code typically handles this in
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 6e6fa28..93d6c6f 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -1119,7 +1119,7 @@
 active, the system accesses these objects using their index position in the
 array and the text they contain is displayed  </p>
 
-<p>Here is an excerpt from the the <a
+<p>Here is an excerpt from the <a
 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a>
 sample's 
 {@link android.widget.RemoteViewsService.RemoteViewsFactory
diff --git a/docs/html/guide/topics/connectivity/wifip2p.jd b/docs/html/guide/topics/connectivity/wifip2p.jd
index bbf30fd..efb3ac7 100644
--- a/docs/html/guide/topics/connectivity/wifip2p.jd
+++ b/docs/html/guide/topics/connectivity/wifip2p.jd
@@ -433,7 +433,7 @@
 
   <p>The {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} method is also
   asynchronous and can notify your activity when a list of peers is available with {@link
-  android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()}, which is defined in the
+  android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()}, which is defined in
   the {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener} interface. The {@link
   android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()} method
   provides you with an {@link android.net.wifi.p2p.WifiP2pDeviceList}, which you can iterate
diff --git a/docs/html/guide/topics/graphics/hardware-accel.jd b/docs/html/guide/topics/graphics/hardware-accel.jd
index 01dd79a..9859c28 100644
--- a/docs/html/guide/topics/graphics/hardware-accel.jd
+++ b/docs/html/guide/topics/graphics/hardware-accel.jd
@@ -512,6 +512,13 @@
         <td class="s7">&#10007;</td>
         <td class="s11">&#10007;</td>
     </tr>
+    <tr>
+        <td class="s10">Local matrix on ComposeShader</td>
+        <td class="s7">&#10007;</td>
+        <td class="s11">&#10007;</td>
+        <td class="s7">&#10007;</td>
+        <td class="s11">&#10003;</td>
+    </tr>
     </tbody>
   </table>
 
diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd
index 6114a4a..3ec71b2 100644
--- a/docs/html/guide/topics/graphics/opengl.jd
+++ b/docs/html/guide/topics/graphics/opengl.jd
@@ -138,7 +138,7 @@
             <li>{@link android.opengl.GLES10}</li>
             <li>{@link android.opengl.GLES10Ext}</li>
             <li>{@link android.opengl.GLES11}</li>
-            <li>{@link android.opengl.GLES10Ext}</li>
+            <li>{@link android.opengl.GLES11Ext}</li>
           </ul>
         </li>
       <li>{@link javax.microedition.khronos.opengles} - This package provides the standard
@@ -289,13 +289,14 @@
     private final String vertexShaderCode =
 
         // This matrix member variable provides a hook to manipulate
-        // the coordinates of objects that use this vertex shader
+        // the coordinates of objects that use this vertex shader.
         "uniform mat4 uMVPMatrix;   \n" +
 
         "attribute vec4 vPosition;  \n" +
         "void main(){               \n" +
-
-        // the matrix must be included as part of gl_Position
+        // The matrix must be included as part of gl_Position
+        // Note that the uMVPMatrix factor *must be first* in order
+        // for the matrix multiplication product to be correct.
         " gl_Position = uMVPMatrix * vPosition; \n" +
 
         "}  \n";
@@ -444,7 +445,7 @@
 
 <p>Beyond the ETC1 format, Android devices have varied support for texture compression based on
 their GPU chipsets and OpenGL implementations. You should investigate texture compression support on
-the the devices you are are targeting to determine what compression types your application should
+the devices you are are targeting to determine what compression types your application should
 support. In order to determine what texture formats are supported on a given device, you must <a
 href="#gl-extension-query">query the device</a> and review the <em>OpenGL extension names</em>,
 which identify what texture compression formats (and other OpenGL features) are supported by the
diff --git a/docs/html/guide/topics/graphics/prop-animation.jd b/docs/html/guide/topics/graphics/prop-animation.jd
index b733624..49d7bb8 100644
--- a/docs/html/guide/topics/graphics/prop-animation.jd
+++ b/docs/html/guide/topics/graphics/prop-animation.jd
@@ -479,7 +479,7 @@
     </li>
 
     <li>Depending on what property or object you are animating, you might need to call the {@link
-    android.view.View#invalidate invalidate()} method on a View force the screen to redraw itself with the
+    android.view.View#invalidate invalidate()} method on a View to force the screen to redraw itself with the
     updated animated values. You do this in the
     {@link android.animation.ValueAnimator.AnimatorUpdateListener#onAnimationUpdate onAnimationUpdate()}
     callback. For example, animating the color property of a Drawable object only cause updates to the
@@ -825,7 +825,7 @@
 
   <h2 id="views">Animating Views</h2>
 
-  <p>The property animation system allow streamlined animation of View objects and offerse
+  <p>The property animation system allow streamlined animation of View objects and offers
   a few advantages over the view animation system. The view
   animation system transformed View objects by changing the way that they were drawn. This was
   handled in the container of each View, because the View itself had no properties to manipulate.
diff --git a/docs/html/guide/topics/graphics/renderscript/graphics.jd b/docs/html/guide/topics/graphics/renderscript/graphics.jd
deleted file mode 100644
index 58676ea..0000000
--- a/docs/html/guide/topics/graphics/renderscript/graphics.jd
+++ /dev/null
@@ -1,994 +0,0 @@
-page.title=Graphics
-parent.title=Renderscript
-parent.link=index.html
-
-@jd:body
-
-  <div id="qv-wrapper">
-    <div id="qv">
-      <h2>In this document</h2>
-
-      <ol>
-        <li>
-          <a href="#creating-graphics-rs">Creating a Graphics Renderscript</a>
-          <ol>
-            <li><a href="#creating-native">Creating the Renderscript file</a></li>
-            <li><a href="#creating-entry">Creating the Renderscript entry point class</a></li>
-            <li><a href="#creating-view">Creating the view class</a></li>
-            <li><a href="#creating-activity">Creating the activity class</a></li>
-          </ol>
-        </li>
-        <li>
-          <a href="#drawing">Drawing</a>
-          <ol>
-            <li><a href="#drawing-rsg">Simple drawing</a></li>
-            <li><a href="#drawing-mesh">Drawing with a mesh</a></li>
-          </ol>
-        </li>
-        <li>
-          <a href="#shaders">Shaders</a>
-          <ol>
-            <li><a href="#shader-bindings">Shader bindings</a></li>
-            <li><a href="#shader-sampler">Defining a sampler</a></li>
-          </ol>
-        </li>
-        <li>
-          <a href="#fbo">Rendering to a Framebuffer Object</a>
-        </li>
-      </ol>
-
-      <h2>Related Samples</h2>
-
-      <ol>
-        <li><a href="{@docRoot}resources/samples/RenderScript/Balls/index.html">Balls</a></li>
-
-        <li><a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Fountain</a></li>
-
-        <li><a href="{@docRoot}resources/samples/RenderScript/FountainFbo/index.html">FountainFbo</a></li>        
-
-        <li><a href="{@docRoot}resources/samples/RenderScript/HelloWorld/index.html">Hello
-World</a></li>
-
-        <li><a
-href="{@docRoot}resources/samples/RenderScript/MiscSamples/index.html">Misc Samples</a></li>
-      </ol>
-    </div>
-  </div>
-
-  <p>Renderscript provides a number of graphics APIs for rendering, both at the Android
-  framework level as well as at the Renderscript runtime level. For instance, the Android framework APIs let you
-  create meshes and define shaders to customize the graphical rendering pipeline. The native
-  Renderscript graphics APIs let you draw the actual meshes to render your scene. You need to
-  be familiar with both APIs to appropriately render graphics on an Android-powered device.</p>
-
-  <h2 id="creating-graphics-rs">Creating a Graphics Renderscript</h2>
-
-  <p>Renderscript applications require various layers of code, so it is useful to create the following
-  files to help keep your application organized:</p>
-
-  <dl>
-    <dt>The Renderscript <code>.rs</code> file</dt>
-
-    <dd>This file contains the logic to do the graphics rendering.</dd>
-
-    <dt>The Renderscript entry point <code>.java</code> class</dt>
-
-    <dd>This class allows the view class to interact with the code defined in the <code>.rs</code>
-    file. This class contains a Renderscript object (instance of
-    <code>ScriptC_<em>renderscript_file</em></code>), which allows your Android framework code to
-    call the Renderscript code. In general, this class does much of the setup for Renderscript
-    such as shader and mesh building and memory allocation and binding. The SDK samples follow the
-    convention of naming this file ActivityRS.java,
-    where Activity is the name of your main activity class.</dd>
-
-    <dt>The view <code>.java</code> class</dt>
-
-    <dd>This class extends {@link android.renderscript.RSSurfaceView} or {@link
-    android.renderscript.RSTextureView} to provide a surface to render on. A {@link
-    android.renderscript.RSSurfaceView} consumes a whole window, but a {@link
-    android.renderscript.RSTextureView} allows you to draw Renderscript graphics inside of a
-    view and add it to a {@link android.view.ViewGroup} alongside
-    other views. In this class, you create a {@link android.renderscript.RenderScriptGL} context object
-    with a call to {@link android.renderscript.RSSurfaceView#createRenderScriptGL
-    RSSurfaceView.createRenderscriptGL()} or {@link android.renderscript.RSTextureView#createRenderScriptGL
-    RSTextureView.createRenderscriptGL()}. The {@link android.renderscript.RenderScriptGL} context object
-    contains information about the current rendering state of Renderscript such as the vertex and
-    fragment shaders. You pass this context object to the Renderscript entry point class, so that
-    class can modify the rendering context if needed and bind the Renderscript code to the context. Once bound,
-    the view class can use the Renderscript code to display graphics.
-    The view class should also implement callbacks for events inherited from {@link
-    android.view.View}, such as {@link android.view.View#onTouchEvent onTouchEvent()} and {@link
-    android.view.View#onKeyDown onKeyDown()} if you want to detect these types of user interactions.
-    The SDK samples follow the convention of naming this file ActivityView.java,
-    where Activity is the name of your main activity class</dd>
-
-    <dt>The activity <code>.java</code> class</dt>
-
-    <dd>This class is the main activity class and sets your {@link android.renderscript.RSSurfaceView} as the main content
-    view for this activity or uses the {@link android.renderscript.RSTextureView} alongside other views.</dd>
-  </dl>
-  <p>Figure 1 describes how these classes interact with one another in a graphics Renderscript:</p>
-  
-  <img src="{@docRoot}images/rs_graphics.png">
-  <p class="img-caption"><strong>Figure 1.</strong> Graphics Renderscript overview</p>
-
-
-  <p>The following sections describe how to create an application that uses a graphics Renderscript by using
-  the <a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Renderscript Fountain
-  sample</a> that is provided in the SDK as a guide (some code has been modified from its original
-  form for simplicity).</p>
-
-  <h3 id="creating-native">Creating the Renderscript file</h3>
-
-  <p>Your Renderscript code resides in <code>.rs</code> and <code>.rsh</code> (headers) files in the
-  <code>&lt;project_root&gt;/src/</code> directory. This code contains the logic to render your
-  graphics and declares all other necessary items such as variables, structs,
-  and pointers. Every graphics <code>.rs</code> file generally contains the following items:</p>
-
-  <ul>
-    <li>A pragma declaration (<code>#pragma rs java_package_name(<em>package.name</em>)</code>) that declares
-    the package name of the <code>.java</code> reflection of this Renderscript.</li>
-
-    <li>A pragma declaration (<code>#pragma version(1)</code>) that declares the version of Renderscript that
-    you are using (1 is the only value for now).</li>
-
-    <li>A <code>#include "rs_graphics.rsh"</code> declaration.</li>
-
-    <li>A <code>root()</code> function. This is the main worker function for your Renderscript and
-    calls Renderscript graphics functions to render scenes. This function is called every time a
-    frame refresh occurs, which is specified as its return value. A <code>0</code> (zero) specified for
-    the return value says to only render the frame when a property of the scene that you are
-    rendering changes. A non-zero positive integer specifies the refresh rate of the frame in
-    milliseconds.
-
-      <p class="note"><strong>Note:</strong> The Renderscript runtime makes its best effort to
-      refresh the frame at the specified rate. For example, if you are creating a live wallpaper
-      and set the return value to 20, the Renderscript runtime renders the wallpaper at 50fps if it has just
-      enough or more resources to do so. It renders as fast as it can if not enough resources
-      are available.</p>
-
-      <p>For more information on using the Renderscript graphics functions, see the <a href=
-      "#drawing">Drawing</a> section.</p>
-    </li>
-
-    <li>An <code>init()</code> function. This allows you to do initialization of your
-    Renderscript before the <code>root()</code> function runs, such as assigning values to variables. This
-    function runs once and is called automatically when the Renderscript starts, before anything
-    else in your Renderscript. Creating this function is optional.</li>
-
-    <li>Any variables, pointers, and structures that you wish to use in your Renderscript code (can
-    be declared in <code>.rsh</code> files if desired)</li>
-  </ul>
-
-  <p>The following code shows how the <code>fountain.rs</code> file is implemented:</p>
-  <pre>
-#pragma version(1)
-
-// Tell which java package name the reflected files should belong to
-#pragma rs java_package_name(com.example.android.rs.fountain)
-
-//declare shader binding
-#pragma stateFragment(parent)
-
-// header with graphics APIs, must include explicitly
-#include "rs_graphics.rsh"
-
-static int newPart = 0;
-
-// the mesh to render
-rs_mesh partMesh;
-
-// the point representing where a particle is rendered
-typedef struct __attribute__((packed, aligned(4))) Point {
-    float2 delta;
-    float2 position;
-    uchar4 color;
-} Point_t;
-Point_t *point;
-
-// main worker function that renders particles onto the screen
-int root() {
-    float dt = min(rsGetDt(), 0.1f);
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-    const float height = rsgGetHeight();
-    const int size = rsAllocationGetDimX(rsGetAllocation(point));
-    float dy2 = dt * (10.f);
-    Point_t * p = point;
-    for (int ct=0; ct &lt; size; ct++) {
-        p-&gt;delta.y += dy2;
-        p-&gt;position += p-&gt;delta;
-        if ((p-&gt;position.y &gt; height) &amp;&amp; (p-&gt;delta.y &gt; 0)) {
-            p-&gt;delta.y *= -0.3f;
-        }
-        p++;
-    }
-
-    rsgDrawMesh(partMesh);
-    return 1;
-}
-
-// adds particles to the screen to render
-static float4 partColor[10];
-void addParticles(int rate, float x, float y, int index, bool newColor)
-{
-    if (newColor) {
-        partColor[index].x = rsRand(0.5f, 1.0f);
-        partColor[index].y = rsRand(1.0f);
-        partColor[index].z = rsRand(1.0f);
-    }
-    float rMax = ((float)rate) * 0.02f;
-    int size = rsAllocationGetDimX(rsGetAllocation(point));
-    uchar4 c = rsPackColorTo8888(partColor[index]);
-
-    Point_t * np = &amp;point[newPart];
-    float2 p = {x, y};
-    while (rate--) {
-        float angle = rsRand(3.14f * 2.f);
-        float len = rsRand(rMax);
-        np-&gt;delta.x = len * sin(angle);
-        np-&gt;delta.y = len * cos(angle);
-        np-&gt;position = p;
-        np-&gt;color = c;
-        newPart++;
-        np++;
-        if (newPart &gt;= size) {
-            newPart = 0;
-            np = &amp;point[newPart];
-        }
-    }
-}
-</pre>
-
-  <h3 id="creating-entry">Creating the Renderscript entry point class</h3>
-
-  <p>When you create a Renderscript (<code>.rs</code>) file, it is helpful to create a
-  corresponding Android framework class that is an entry point into the <code>.rs</code> file.
-  The most important thing this class does is receive a {@link android.renderscript.RenderScriptGL} rendering context
-  object from the <a href="#creating-view">view class</a> and binds the actual Renderscript
-  code to the rendering context. This notifies your view class of the code that it needs
-  to render graphics.
-  </p>
-
-  <p>In addition, this class should contain all of the things needed to set up Renderscript.
-  Some important things that you need to do in this class are:</p>
-
-  <ul>
-    <li>Create a Renderscript object 
-  <code>ScriptC_<em>rs_filename</em></code>. The Renderscript object is attached to the Renderscript bytecode, which is platform-independent and
-  gets compiled on the device when the Renderscript application runs. The bytecode is referenced
-  as a raw resource and is passed into the constructor for the Renderscript object.
-  For example, this is how the <a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Fountain</a>
-  sample creates the Renderscript object:
-  <pre>
-  RenderScriptGL rs;  //obtained from the view class
-  Resources res;      //obtained from the view class
-  ...
-  ScriptC_fountain mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
-  </pre>
-  </li>
-  <li>Allocate any necessary memory and bind it to your Renderscript code via the Renderscript object.</li>
-  <li>Build any necessary meshes and bind them to the Renderscript code via the Renderscript object.</li>
-  <li>Create any necessary programs and bind them to the Renderscript code via the Renderscript object.</li>
-  </ul>
-
-  <p>The following code shows how the <a href=
-  "{@docRoot}resources/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainRS.html">
-  FountainRS</a> class is implemented:</p>
-  <pre>
-package com.example.android.rs.fountain;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-public class FountainRS {
-    public static final int PART_COUNT = 50000;
-
-    public FountainRS() {
-    }
-
-    /**
-     * This provides us with the Renderscript context and resources
-     * that allow us to create the Renderscript object
-     */
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    // Renderscript object
-    private ScriptC_fountain mScript;
-
-    // Called by the view class to initialize the Renderscript context and renderer
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-
-        /**
-         * Create a shader and bind to the Renderscript context
-         */
-        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
-        pfb.setVaryingColor(true);
-        rs.bindProgramFragment(pfb.create());
-
-        /**
-         * Allocate memory for the particles to render and create the mesh to draw
-         */
-        ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
-        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
-        smb.addVertexAllocation(points.getAllocation());
-        smb.addIndexSetType(Mesh.Primitive.POINT);
-        Mesh sm = smb.create();
-
-       /**
-        * Create and bind the Renderscript object to the Renderscript context
-        */
-        mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
-        mScript.set_partMesh(sm);
-        mScript.bind_point(points);
-        mRS.bindRootScript(mScript);
-    }
-
-    boolean holdingColor[] = new boolean[10];
-
-    /**
-     * Calls Renderscript functions (invoke_addParticles)
-     * via the Renderscript object to add particles to render
-     * based on where a user touches the screen.
-     */
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-        if (id &gt;= holdingColor.length) {
-            return;
-        }
-        int rate = (int)(pressure * pressure * 500.f);
-        if (rate &gt; 500) {
-            rate = 500;
-        }
-        if (rate &gt; 0) {
-            mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
-            holdingColor[id] = true;
-        } else {
-            holdingColor[id] = false;
-        }
-
-    }
-}
-</pre>
-
-
-  <h3 id="creating-view">Creating the view class</h3>
-
-
-  <p>To display graphics, you need a view to render on. Create a class that extends {@link
-  android.renderscript.RSSurfaceView} or {@link android.renderscript.RSTextureView}. This class
-  allows you to create a {@link android.renderscript.RenderScriptGL} context object by calling and
-  pass it to the Rendscript entry point class to bind the two. Once bound, the content is aware
-  of the code that it needs to use to render graphics with. If your Renderscript code
-  depends on any type of information that the view is aware of, such as touches from the user,
-  you can also use this class to relay that information to the Renderscript entry point class.
-  The following code shows how the <code>FountainView</code> class is implemented:</p>
-  <pre>
-package com.example.android.rs.fountain;
-
-import android.renderscript.RSTextureView;
-import android.renderscript.RenderScriptGL;
-import android.content.Context;
-import android.view.MotionEvent;
-
-public class FountainView extends RSTextureView {
-
-    public FountainView(Context context) {
-        super(context);
-    }
-    // Renderscript context
-    private RenderScriptGL mRS;
-    // Renderscript entry point object that calls Renderscript code
-    private FountainRS mRender;
-
-    /**
-     * Create Renderscript context and initialize Renderscript entry point
-     */
-    &#064;Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        android.util.Log.e("rs", "onAttachedToWindow");
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRender = new FountainRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    &#064;Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        android.util.Log.e("rs", "onDetachedFromWindow");
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-
-    /**
-     * Use callbacks to relay data to Renderscript entry point class
-     */
-    &#064;Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        int act = ev.getActionMasked();
-        if (act == ev.ACTION_UP) {
-            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
-            return false;
-        } else if (act == MotionEvent.ACTION_POINTER_UP) {
-            // only one pointer going up, we can get the index like this
-            int pointerIndex = ev.getActionIndex();
-            int pointerId = ev.getPointerId(pointerIndex);
-            mRender.newTouchPosition(0, 0, 0, pointerId);
-        }
-        int count = ev.getHistorySize();
-        int pcount = ev.getPointerCount();
-
-        for (int p=0; p &lt; pcount; p++) {
-            int id = ev.getPointerId(p);
-            mRender.newTouchPosition(ev.getX(p),
-                                     ev.getY(p),
-                                     ev.getPressure(p),
-                                     id);
-
-            for (int i=0; i &lt; count; i++) {
-                mRender.newTouchPosition(ev.getHistoricalX(p, i),
-                                         ev.getHistoricalY(p, i),
-                                         ev.getHistoricalPressure(p, i),
-                                         id);
-            }
-        }
-        return true;
-    }
-}
-</pre>
-
-  <h3 id="creating-activity">Creating the activity class</h3>
-
-  <p>Applications that use Renderscript still behave like normal Android applications, so you
-   need an activity class that handles activity lifecycle callback events appropriately. The activity class
-   also sets your {@link android.renderscript.RSSurfaceView} view class to be the main content view of the
-   activity or uses your {@link android.renderscript.RSTextureView}
-  in a {@link android.view.ViewGroup} alongside other views.</p>
-
-  <p>The following code shows how the <a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Fountain</a>
-  sample declares its activity class:</p>
-  <pre>
-package com.example.android.rs.fountain;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-
-public class Fountain extends Activity {
-
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private FountainView mView;
-
-    &#064;Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as 
-        // the content of our activity
-        mView = new FountainView(this);
-        setContentView(mView);
-    }
-
-    &#064;Override
-    protected void onResume() {
-        Log.e("rs", "onResume");
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    &#064;Override
-    protected void onPause() {
-        Log.e("rs", "onPause");
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-}
-</pre>
-
-<p>Now that you have an idea of what is involved in a Renderscript graphics application, you can
-start building your own. It might be easiest to begin with one of the
-<a href="{@docRoot}resources/samples/RenderScript/index.html">Renderscript samples</a> as a starting
-point if this is your first time using Renderscript.</p>
-
-  <h2 id="drawing">Drawing</h2>
-  <p>The following sections describe how to use the graphics functions to draw with Renderscript.</p>
-
-  <h3 id="drawing-rsg">Simple drawing</h3>
-
-  <p>The native Renderscript APIs provide a few convenient functions to easily draw a polygon or text to
-  the screen. You call these in your <code>root()</code> function to have them render to the {@link
-  android.renderscript.RSSurfaceView} or {@link android.renderscript.RSTextureView}. These functions are
-  available for simple drawing and should not be used for complex graphics rendering:</p>
-
-  <ul>
-    <li><code>rsgDrawRect()</code>: Sets up a mesh and draws a rectangle to the screen. It uses the
-    top left vertex and bottom right vertex of the rectangle to draw.</li>
-
-    <li><code>rsgDrawQuad()</code>: Sets up a mesh and draws a quadrilateral to the screen.</li>
-
-    <li><code>rsgDrawQuadTexCoords()</code>: Sets up a mesh and draws a quadrilateral to the screen
-    using the provided coordinates of a texture.</li>
-
-    <li><code>rsgDrawText()</code>: Draws specified text to the screen. Use <code>rsgFontColor()</code>
-    to set the color of the text.</li>
-  </ul>
-
-  <h3 id="drawing-mesh">Drawing with a mesh</h3>
-
-  <p>When you want to render complex scenes to the screen, instantiate a {@link
-  android.renderscript.Mesh} and draw it with <code>rsgDrawMesh()</code>. A {@link
-  android.renderscript.Mesh} is a collection of allocations that represent vertex data (positions,
-  normals, texture coordinates) and index data that provides information on how to draw triangles
-  and lines with the provided vertex data. You can build a Mesh in three different ways:</p>
-
-  <ul>
-    <li>Build the mesh with the {@link android.renderscript.Mesh.TriangleMeshBuilder} class, which
-    allows you to specify a set of vertices and indices for each triangle that you want to draw.</li>
-
-    <li>Build the mesh using an {@link android.renderscript.Allocation} or a set of {@link
-    android.renderscript.Allocation}s with the {@link android.renderscript.Mesh.AllocationBuilder}
-    class. This approach allows you to build a mesh with vertices already stored in memory, which allows you
-    to specify the vertices in Renderscript or Android framework code.</li>
-
-    <li>Build the mesh with the {@link android.renderscript.Mesh.Builder} class. You should use
-    this convenience method when you know the data types you want to use to build your mesh, but
-    don't want to make separate memory allocations like with {@link
-    android.renderscript.Mesh.AllocationBuilder}. You can specify the types that you want and this
-    mesh builder automatically creates the memory allocations for you.</li>
-  </ul>
-
-  <p>To create a mesh using the {@link android.renderscript.Mesh.TriangleMeshBuilder}, you need to
-  supply it with a set of vertices and the indices for the vertices that comprise the triangle. For
-  example, the following code specifies three vertices, which are added to an internal array,
-  indexed in the order they were added. The call to {@link
-  android.renderscript.Mesh.TriangleMeshBuilder#addTriangle addTriangle()} draws the triangle with
-  vertex 0, 1, and 2 (the vertices are drawn counter-clockwise).</p>
-  <pre>
-int float2VtxSize = 2;
-Mesh.TriangleMeshBuilder triangles = new Mesh.TriangleMeshBuilder(renderscriptGL,
-float2VtxSize, Mesh.TriangleMeshBuilder.COLOR);
-triangles.addVertex(300.f, 300.f);
-triangles.addVertex(150.f, 450.f);
-triangles.addVertex(450.f, 450.f);
-triangles.addTriangle(0 , 1, 2);
-Mesh smP = triangle.create(true);
-script.set_mesh(smP);
-</pre>
-
-  <p>To draw a mesh using the {@link android.renderscript.Mesh.AllocationBuilder}, you need to
-  supply it with one or more allocations that contain the vertex data:</p>
-  <pre>
-Allocation vertices;
-
-...
-Mesh.AllocationBuilder triangle = new Mesh.AllocationBuilder(mRS);
-smb.addVertexAllocation(vertices.getAllocation());
-smb.addIndexSetType(Mesh.Primitive.TRIANGLE);
-Mesh smP = smb.create();
-script.set_mesh(smP);
-</pre>
-
-  <p>In your Renderscript code, draw the built mesh to the screen:</p>
-  <pre>
-rs_mesh mesh;
-...
-
-int root(){
-...
-rsgDrawMesh(mesh);
-...
-return 0; //specify a non zero, positive integer to specify the frame refresh.
-          //0 refreshes the frame only when the mesh changes.
-}
-</pre>
-
-  <h2 id="shader">Programs</h2>
-
-  <p>You can attach four program objects to the {@link android.renderscript.RenderScriptGL} context
-  to customize the rendering pipeline. For example, you can create vertex and fragment shaders in
-  GLSL or build a raster program object that controls culling. The four programs mirror a
-  traditional graphical rendering pipeline:</p>
-
-  <table>
-    <tr>
-      <th>Android Object Type</th>
-
-      <th>Renderscript Native Type</th>
-
-      <th>Description</th>
-    </tr>
-
-    <tr>
-      <td>{@link android.renderscript.ProgramVertex}</td>
-
-      <td>rs_program_vertex</td>
-
-      <td>
-        <p>The Renderscript vertex program, also known as a vertex shader, describes the stage in
-        the graphics pipeline responsible for manipulating geometric data in a user-defined way.
-        The object is constructed by providing Renderscript with the following data:</p>
-
-        <ul>
-          <li>An {@link android.renderscript.Element} describing its varying inputs or attributes</li>
-
-          <li>GLSL shader string that defines the body of the program</li>
-
-          <li>a {@link android.renderscript.Type} that describes the layout of an
-          Allocation containing constant or uniform inputs</li>
-        </ul>
-
-        <p>Once the program is created, bind it to the {@link android.renderscript.RenderScriptGL}
-        graphics context by calling {@link android.renderscript.RenderScriptGL#bindProgramVertex
-        bindProgramVertex()}. It is then used for all subsequent draw calls until you bind a new
-        program. If the program has constant inputs, the user needs to bind an allocation
-        containing those inputs. The allocation's type must match the one provided during creation.
-        </p>
-
-        <p>The Renderscript runtime then does all the necessary plumbing to send those constants to
-        the graphics hardware. Varying inputs to the shader, such as position, normal, and texture
-        coordinates are matched by name between the input {@link android.renderscript.Element}
-        and the mesh object that is being drawn. The signatures don't have to be exact or in any
-        strict order. As long as the input name in the shader matches a channel name and size
-        available on the mesh, the Renderscript runtime handles connecting the two. Unlike OpenGL
-        there is no need to link the vertex and fragment programs.</p>
-
-        <p>To bind shader constants to the program, declare a <code>struct</code> that contains the necessary
-        shader constants in your Renderscript code. This <code>struct</code> is generated into a
-        reflected class that you can use as a constant input element during the program's creation.
-        It is an easy way to create an instance of this <code>struct</code> as an allocation. You would then
-        bind this {@link android.renderscript.Allocation} to the program and the
-        Renderscript runtime sends the data that is contained in the <code>struct</code> to the hardware
-        when necessary. To update shader constants, you change the values in the
-        {@link android.renderscript.Allocation} and notify the Renderscript
-        code of the change.</p>
-
-        <p>The {@link android.renderscript.ProgramVertexFixedFunction.Builder} class also
-        lets you build a simple vertex shader without writing GLSL code.
-        </p>
-      </td>
-    </tr>
-
-    <tr>
-      <td>{@link android.renderscript.ProgramFragment}</td>
-
-      <td>rs_program_fragment</td>
-
-      <td>
-        <p>The Renderscript fragment program, also known as a fragment shader, is responsible for
-        manipulating pixel data in a user-defined way. It's constructed from a GLSL shader string
-        containing the program body, texture inputs, and a {@link android.renderscript.Type}
-        object that describes the constants
-        used by the program. Like the vertex programs, when an {@link android.renderscript.Allocation}
-        with constant input
-        values is bound to the shader, its values are sent to the graphics program automatically.
-        Note that the values inside the {@link android.renderscript.Allocation} are not explicitly tracked.
-        If they change between two draw calls using the same program object, notify the runtime of that change by
-        calling <code>rsgAllocationSyncAll()</code>, so it can send the new values to hardware. Communication
-        between the vertex and fragment programs is handled internally in the GLSL code. For
-        example, if the fragment program is expecting a varying input called <code>varTex0</code>, the GLSL code
-        inside the program vertex must provide it.</p>
-
-        <p>To bind shader constructs to the program, declare a <code>struct</code> that contains the necessary
-        shader constants in your Renderscript code. This <code>struct</code> is generated into a
-        reflected class that you can use as a constant input element during the program's creation.
-        It is an easy way to create an instance of this <code>struct</code> as an allocation. You would then
-        bind this {@link android.renderscript.Allocation} to the program and the
-        Renderscript runtime sends the data that is contained in the <code>struct</code> to the hardware
-        when necessary. To update shader constants, you change the values in the
-        {@link android.renderscript.Allocation} and notify the Renderscript
-        code of the change.</p>
-
-        <p>The {@link android.renderscript.ProgramFragmentFixedFunction.Builder} class also
-        lets you build a simple fragment shader without writing GLSL code.
-        </p>
-      </td>
-    </tr>
-
-    <tr>
-      <td>{@link android.renderscript.ProgramStore}</td>
-
-      <td>rs_program_store</td>
-
-      <td>The Renderscript store program contains a set of parameters that control how the graphics
-      hardware writes to the framebuffer. It could be used to enable and disable depth writes and
-      testing, setup various blending modes for effects like transparency and define write masks
-      for color components.</td>
-    </tr>
-
-    <tr>
-      <td>{@link android.renderscript.ProgramRaster}</td>
-
-      <td>rs_program_raster</td>
-
-      <td>The Renderscript raster program is primarily used to specify whether point sprites are enabled and to
-      control the culling mode. By default back faces are culled.</td>
-    </tr>
-  </table>
-
-  <p>The following example defines a vertex shader in GLSL and binds it to a Renderscript context object:</p>
-  <pre>
-    private RenderScriptGL glRenderer;      //rendering context
-    private ScriptField_Point mPoints;      //vertices
-    private ScriptField_VpConsts mVpConsts; //shader constants
-
-    ...
-
-     ProgramVertex.Builder sb = new ProgramVertex.Builder(glRenderer);
-        String t =  "varying vec4 varColor;\n" +
-                    "void main() {\n" +
-                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
-                    "  pos.xy = ATTRIB_position;\n" +
-                    "  gl_Position = UNI_MVP * pos;\n" +
-                    "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
-                    "  gl_PointSize = ATTRIB_size;\n" +
-                    "}\n";
-        sb.setShader(t);
-        sb.addConstant(mVpConsts.getType());
-        sb.addInput(mPoints.getElement());
-        ProgramVertex pvs = sb.create();
-        pvs.bindConstants(mVpConsts.getAllocation(), 0);
-        glRenderer.bindProgramVertex(pvs);
-</pre>
-
-
-  <p>The <a href=
-  "{@docRoot}resources/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.html">
-  RsRenderStatesRS</a> sample has many examples on how to create a shader without writing GLSL.</p>
-
-  <h3 id="shader-bindings">Program bindings</h3>
-
-  <p>You can also declare four pragmas that control default program bindings to the {@link
-  android.renderscript.RenderScriptGL} context when the script is executing:</p>
-
-  <ul>
-    <li><code>stateVertex</code></li>
-
-    <li><code>stateFragment</code></li>
-
-    <li><code>stateRaster</code></li>
-
-    <li><code>stateStore</code></li>
-  </ul>
-
-  <p>The possible values for each pragma are <code>parent</code> or <code>default</code>. Using
-  <code>default</code> binds the shaders to the graphical context with the system defaults.</p>
-
-  <p>Using <code>parent</code> binds the shaders in the same manner as it is bound in the calling
-  script. If this is the root script, the parent state is taken from the bind points that are set
-  by the {@link android.renderscript.RenderScriptGL} bind methods.</p>
-
-  <p>For example, you can define this at the top of your graphics Renderscript code to have
-  the vertex and store programs inherent the bind properties from their parent scripts:</p>
-  <pre>
-#pragma stateVertex(parent)
-#pragma stateStore(parent)
-</pre>
-
-  <h3 id="shader-sampler">Defining a sampler</h3>
-
-  <p>A {@link android.renderscript.Sampler} object defines how data is extracted from textures.
-  Samplers are bound to a {@link android.renderscript.ProgramFragment} alongside the texture
-  whose sampling they control. These
-  objects are used to specify such things as edge clamping behavior, whether mip-maps are used, and
-  the amount of anisotropy required. There might be situations where hardware does not support the
-  desired behavior of the sampler. In these cases, the Renderscript runtime attempts to provide the
-  closest possible approximation. For example, the user requested 16x anisotropy, but only 8x was
-  set because it's the best available on the hardware.</p>
-
-  <p>The <a href=
-  "{@docRoot}resources/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.html">
-  RsRenderStatesRS</a> sample has many examples on how to create a sampler and bind it to a
-  Fragment program.</p>
-
-
-
-<h2 id="fbo">Rendering to a Framebuffer Object</h2>
-
-<p>Framebuffer objects allow you to render offscreen instead of in the default onscreen
-framebuffer. This approach might be useful for situations where you need to post-process a texture before
-rendering it to the screen, or when you want to composite two scenes in one such as rendering a rear-view
-mirror of a car. There are two buffers associated with a framebuffer object: a color buffer
-and a depth buffer. The color buffer (required) contains the actual pixel data of the scene
-that you are rendering, and the depth buffer (optional) contains the values necessary to figure
-out what vertices are drawn depending on their z-values.</p>
-
-<p>In general, you need to do the following to render to a framebuffer object:</p>
-
-<ul>
-  <li>Create {@link android.renderscript.Allocation} objects for the color buffer and
-  depth buffer (if needed). Specify the {@link
-  android.renderscript.Allocation#USAGE_GRAPHICS_RENDER_TARGET} usage attribute for these
-  allocations to notify the Renderscript runtime to use these allocations for the framebuffer
-  object. For the color buffer allocation, you most likely need to declare the {@link
-  android.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE} usage attribute
-  to use the color buffer as a texture, which is the most common use of the framebuffer object.</li>
-
-  <li>Tell the Renderscript runtime to render to the framebuffer object instead of the default
-  framebuffer by calling <code>rsgBindColorTarget()</code> and passing it the color buffer
-  allocation. If applicable, call <code>rsgBindDepthTarget()</code> passing in the depth buffer
-  allocation as well.</li>
-
-  <li>Render your scene normally with the <code>rsgDraw</code> functions. The scene will be
-  rendered into the color buffer instead of the default onscreen framebuffer.</li>
-
-  <li>When done, tell the Renderscript runtime stop rendering to the color buffer and back
-  to the default framebuffer by calling <code>rsgClearAllRenderTargets()</code>.</li>
-
-  <li>Create a fragment shader and bind a the color buffer to it as a texture.</li>
-
-  <li>Render your scene to the default framebuffer. The texture will be used according
-  to the way you setup your fragment shader.</li>
-</ul>
-
-<p>The following example shows you how to render to a framebuffer object by modifying the
-<a href="{@docRoot}guide/resources/renderscript/Fountain/">Fountain</a> Renderscript sample. The end
-result is the <a href="{@docRoot}guide/resources/renderscript/FountainFBO/">FountainFBO</a> sample.
-The modifications render the exact same scene into a framebuffer object as it does the default
-framebuffer. The framebuffer object is then rendered into the default framebuffer in a small
-area at the top left corner of the screen.</p>
-
-<ol>
-  <li>Modify <code>fountain.rs</code> and add the following global variables. This creates setter
-  methods when this file is reflected into a <code>.java</code> file, allowing you to allocate
-  memory in your Android framework code and binding it to the Renderscript runtime.
-<pre>
-//allocation for color buffer
-rs_allocation gColorBuffer;
-//fragment shader for rendering without a texture (used for rendering to framebuffer object)
-rs_program_fragment gProgramFragment;
-//fragment shader for rendering with a texture (used for rendering to default framebuffer)
-rs_program_fragment gTextureProgramFragment;
-</pre>
-  </li>
-
-  <li>Modify the root function of <code>fountain.rs</code> to look like the following code. The
-  modifications are commented:
-<pre>
-int root() {
-    float dt = min(rsGetDt(), 0.1f);
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-    const float height = rsgGetHeight();
-    const int size = rsAllocationGetDimX(rsGetAllocation(point));
-    float dy2 = dt * (10.f);
-    Point_t * p = point;
-    for (int ct=0; ct < size; ct++) {
-        p->delta.y += dy2;
-        p->position += p->delta;
-        if ((p->position.y > height) && (p->delta.y > 0)) {
-            p->delta.y *= -0.3f;
-        }
-        p++;
-    }
-    //Tell Renderscript runtime to render to the frame buffer object
-    rsgBindColorTarget(gColorBuffer, 0);
-    //Begin rendering on a white background
-    rsgClearColor(1.f, 1.f, 1.f, 1.f);
-    rsgDrawMesh(partMesh);
-
-    //When done, tell Renderscript runtime to stop rendering to framebuffer object
-    rsgClearAllRenderTargets();
-
-    //Bind a new fragment shader that declares the framebuffer object to be used as a texture
-    rsgBindProgramFragment(gTextureProgramFragment);
-
-    //Bind the framebuffer object to the fragment shader at slot 0 as a texture
-    rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer);
-    //Draw a quad using the framebuffer object as the texture
-    float startX = 10, startY = 10;
-    float s = 256;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
-                         startX, startY + s, 0, 0, 0,
-                         startX + s, startY + s, 0, 1, 0,
-                         startX + s, startY, 0, 1, 1);
-
-    //Rebind the original fragment shader to render as normal
-    rsgBindProgramFragment(gProgramFragment);
-
-    //Render the main scene
-    rsgDrawMesh(partMesh);
-
-    return 1;
-}
-</pre>
-  </li>
-
-  <li>In the <code>FountainRS.java</code> file, modify the <code>init()</code> method to look
-  like the following code. The modifications are commented:
-
-<pre>
-/* Add necessary members */
-private ScriptC_fountainfbo mScript;
-private Allocation mColorBuffer;
-private ProgramFragment mProgramFragment;
-private ProgramFragment mTextureProgramFragment;
-
-public void init(RenderScriptGL rs, Resources res) {
-    mRS = rs;
-    mRes = res;
-
-    ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
-
-    Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
-    smb.addVertexAllocation(points.getAllocation());
-    smb.addIndexSetType(Mesh.Primitive.POINT);
-    Mesh sm = smb.create();
-
-    mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo);
-    mScript.set_partMesh(sm);
-    mScript.bind_point(points);
-
-    ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
-    pfb.setVaryingColor(true);
-    mProgramFragment = pfb.create();
-    mScript.set_gProgramFragment(mProgramFragment);
-
-    /* Second fragment shader to use a texture (framebuffer object) to draw with */
-    pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-        ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-
-    /* Set the fragment shader in the Renderscript runtime */
-    mTextureProgramFragment = pfb.create();
-    mScript.set_gTextureProgramFragment(mTextureProgramFragment);
-
-    /* Create the allocation for the color buffer */
-    Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-    colorBuilder.setX(256).setY(256);
-    mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(),
-    Allocation.USAGE_GRAPHICS_TEXTURE |
-    Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-
-    /* Set the allocation in the Renderscript runtime */
-    mScript.set_gColorBuffer(mColorBuffer);
-
-    mRS.bindRootScript(mScript);
-}
-</pre>
-
-<p class="note"><strong>Note:</strong> This sample doesn't use a depth buffer, but the following code
-shows you how to declare an example depth buffer if you need to use
-one for your application. The depth buffer must have the same dimensions as the color buffer:
-
-<pre>
-Allocation mDepthBuffer;
-
-...
-
-Type.Builder b = new Type.Builder(mRS, Element.createPixel(mRS, DataType.UNSIGNED_16,
-    DataKind.PIXEL_DEPTH));
-b.setX(256).setY(256);
-mDepthBuffer = Allocation.createTyped(mRS, b.create(),
-Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-
-</pre>
-</p>
-</li>
-
-  <li>Run and use the sample. The smaller, white quad on the top-left corner is using the
-  framebuffer object as a texture, which renders the same scene as the main rendering.</li>
-</ol>
diff --git a/docs/html/guide/topics/location/index.jd b/docs/html/guide/topics/location/index.jd
index 3217196..c4e8829 100644
--- a/docs/html/guide/topics/location/index.jd
+++ b/docs/html/guide/topics/location/index.jd
@@ -59,7 +59,9 @@
 
 <h2 id="maps">Google Maps Android API</h2>
 
-<p>With the Google Maps Android API, you can add maps to your app that are based on Google
+<p>With the 
+<a href="http://developers.google.com/maps/documentation/android/">Google Maps Android API</a>,
+you can add maps to your app that are based on Google
 Maps data. The API automatically handles access to Google Maps servers, data downloading,
 map display, and touch gestures on the map. You can also use API calls to add markers,
 polygons and overlays, and to change the user's view of a particular map area.</p>
@@ -85,6 +87,6 @@
 
 <p>To integrate Google Maps into your app, you need to install the Google Play services
 libraries for your Android SDK. For more details, read about <a
-href="{@docRoot}google/play-services/index.html">Google Play services</a>.</p>
+href="{@docRoot}google/play-services/maps.html">Google Play services</a>.</p>
 
 
diff --git a/docs/html/guide/topics/manifest/activity-alias-element.jd b/docs/html/guide/topics/manifest/activity-alias-element.jd
index ba2c154..d3df08b 100644
--- a/docs/html/guide/topics/manifest/activity-alias-element.jd
+++ b/docs/html/guide/topics/manifest/activity-alias-element.jd
@@ -89,7 +89,7 @@
 
 <dt><a name="label"></a>{@code android:label}</dt>
 <dd>A user-readable label for the alias when presented to users through the alias.
-See the the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> element's 
+See the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> element's
 <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#label">label</a></code> attribute for more information.
 </p></dd>
 
@@ -132,4 +132,4 @@
 <dt>see also:</dt>
 <dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code></dd>
 
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index 2aedaec..c9f505f 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -217,7 +217,7 @@
   </tr><tr>
   <td>"{@code uiMode}"</td>
    <td>The user interface mode has changed &mdash; this can be caused when the user places the
-device into a desk/car dock or when the the night mode changes. See {@link
+device into a desk/car dock or when the night mode changes. See {@link
 android.app.UiModeManager}. 
     <em>Added in API level 8</em>.</td>
   </tr><tr>
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index 8fd91de..766d2d7 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -85,6 +85,9 @@
 The subtype can be the asterisk wildcard ({@code *}) to indicate that any 
 subtype matches.
 
+<p>It's common for an intent filter to declare a {@code &lt;data>} that includes
+only the {@code android:mimeType} attribute.</p>
+
 <p class="note">Note: MIME type matching in the Android framework is
 case-sensitive, unlike formal RFC MIME types.  As a result, you should always
 specify MIME types using lowercase letters.</p>
diff --git a/docs/html/guide/topics/manifest/intent-filter-element.jd b/docs/html/guide/topics/manifest/intent-filter-element.jd
index f90541c..68da981 100644
--- a/docs/html/guide/topics/manifest/intent-filter-element.jd
+++ b/docs/html/guide/topics/manifest/intent-filter-element.jd
@@ -119,7 +119,11 @@
 
 <p>
 The value must be an integer, such as "{@code 100}".  Higher numbers have a
-higher priority.
+higher priority. The default value is 0.
+The value must be greater than -1000 and less than 1000.</p>
+
+<p>Also see {@link android.content.IntentFilter#setPriority
+setPriority()}.
 </p></dd>
 
 </dl></dd>
diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
index 85a871d..56a214c 100644
--- a/docs/html/guide/topics/manifest/meta-data-element.jd
+++ b/docs/html/guide/topics/manifest/meta-data-element.jd
@@ -80,7 +80,7 @@
 </tr><tr>
   <td>Color value, in the form "{@code #rgb}", "{@code #argb}", 
       "{@code #rrggbb}", or "{@code #aarrggbb}"</td>
-  <td>{@link android.os.Bundle#getString(String) getString()}</td>
+  <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
 </tr><tr>
   <td>Float value, such as "{@code 1.23}"</td>
   <td>{@link android.os.Bundle#getFloat(String) getFloat()}</td>
diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
index f53b062..3cd4511 100644
--- a/docs/html/guide/topics/providers/calendar-provider.jd
+++ b/docs/html/guide/topics/providers/calendar-provider.jd
@@ -605,7 +605,7 @@
 Uri updateUri = null;
 // The new title for the event
 values.put(Events.TITLE, &quot;Kickboxing&quot;); 
-myUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
 int rows = getContentResolver().update(updateUri, values, null, null);
 Log.i(DEBUG_TAG, &quot;Rows updated: &quot; + rows);  </pre>
 
@@ -816,7 +816,7 @@
   <tr>
     <td>{@link android.provider.CalendarContract.Instances#END_MINUTE}</td>
     
-    <td>The end minute of the instance measured from midnight in the the
+    <td>The end minute of the instance measured from midnight in the
 Calendar's time zone.</td>
     
   </tr>
diff --git a/docs/html/guide/topics/resources/accessing-resources.jd b/docs/html/guide/topics/resources/accessing-resources.jd
index 0673b6f..8f99653 100644
--- a/docs/html/guide/topics/resources/accessing-resources.jd
+++ b/docs/html/guide/topics/resources/accessing-resources.jd
@@ -50,7 +50,7 @@
 <p>When your application is compiled, {@code aapt} generates the {@code R} class, which contains
 resource IDs for all the resources in your {@code
 res/} directory. For each type of resource, there is an {@code R} subclass (for example,
-{@code R.drawable} for all drawable resources) and for each resource of that type, there is a static
+{@code R.drawable} for all drawable resources), and for each resource of that type, there is a static
 integer (for example, {@code R.drawable.icon}). This integer is the resource ID that you can use
 to retrieve your resource.</p>
 
@@ -68,7 +68,7 @@
 
 <p>There are two ways you can access a resource:</p>
 <ul>
-  <li><strong>In code:</strong> Using an static integer from a sub-class of your {@code R}
+  <li><strong>In code:</strong> Using a static integer from a sub-class of your {@code R}
 class, such as:
     <pre class="classic no-pretty-print">R.string.hello</pre>
     <p>{@code string} is the resource type and {@code hello} is the resource name. There are many
@@ -264,11 +264,13 @@
     android:text=&quot;&#64;string/hello&quot; /&gt;
 </pre>
 
-<p class="note"><strong>Note:</strong> You should use string resources at all times, so that your
-application can be localized for other languages. For information about creating alternative
+<p class="note"><strong>Note:</strong> You should use string resources at 
+all times, so that your application can be localized for other languages. 
+For information about creating alternative
 resources (such as localized strings), see <a
 href="providing-resources.html#AlternativeResources">Providing Alternative
-Resources</a>.</p>
+Resources</a>. For a complete guide to localizing your application for other languages,
+see <a href="localization.html">Localization</a>.</p>
 
 <p>You can even use resources in XML to create aliases. For example, you can create a
 drawable resource that is an alias for another drawable resource:</p>
diff --git a/docs/html/guide/topics/resources/animation-resource.jd b/docs/html/guide/topics/resources/animation-resource.jd
index 3af52aa..e5cac88 100644
--- a/docs/html/guide/topics/resources/animation-resource.jd
+++ b/docs/html/guide/topics/resources/animation-resource.jd
@@ -217,7 +217,7 @@
     </dd>
 
 <dt id="val-animator-element"><code>&lt;animator&gt;</code></dt>
-    <dd>Animates a over a specified amount of time.
+    <dd>Performs an animation over a specified amount of time.
     Represents a {@link android.animation.ValueAnimator}.
 
       <p class="caps">attributes:</p>
@@ -593,7 +593,7 @@
 <p>All interpolators available in Android are subclasses of the {@link
 android.view.animation.Interpolator} class. For each interpolator class, Android
 includes a public resource you can reference in order to apply the interpolator to an animation
-using the the {@code android:interpolator} attribute.
+using the {@code android:interpolator} attribute.
 The following table specifies the resource to use for each interpolator:</p>
 
 <table>
diff --git a/docs/html/guide/topics/resources/layout-resource.jd b/docs/html/guide/topics/resources/layout-resource.jd
index 380ab15..366ddc8 100644
--- a/docs/html/guide/topics/resources/layout-resource.jd
+++ b/docs/html/guide/topics/resources/layout-resource.jd
@@ -135,7 +135,7 @@
     </dd>
   <dt id="requestfocus-element"><code>&lt;requestFocus&gt;</code></dt>
     <dd>Any element representing a {@link android.view.View} object can include this empty element,
-    which gives it's parent initial focus on the screen. You can have only one of these
+    which gives its parent initial focus on the screen. You can have only one of these
     elements per file.</dd>
 
   <dt id="include-element"><code>&lt;include&gt;</code></dt>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index b311b7f..5097cc4 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -376,7 +376,7 @@
 screen area. Specifically, the device's smallestWidth is the shortest of the screen's available
 height and width (you may also think of it as the "smallest possible width" for the screen). You can
 use this qualifier to ensure that, regardless of the screen's current orientation, your
-application's has at least {@code &lt;N&gt;} dps of width available for it UI.</p>
+application has at least {@code &lt;N&gt;} dps of width available for its UI.</p>
         <p>For example, if your layout requires that its smallest dimension of screen area be at
 least 600 dp at all times, then you can use this qualifer to create the layout resources, {@code
 res/layout-sw600dp/}. The system will use these resources only when the smallest dimension of
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index b9a26d6..e24681a 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -722,6 +722,7 @@
     // Get the SearchView and set the searchable configuration
     SearchManager searchManager = (SearchManager) {@link android.app.Activity#getSystemService getSystemService}(Context.SEARCH_SERVICE);
     SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+    // Assumes current activity is the searchable activity
     searchView.setSearchableInfo(searchManager.getSearchableInfo({@link android.app.Activity#getComponentName()}));
     searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
 
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 3115c8f..db09e7d 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1,4 +1,5 @@
 page.title=Action Bar
+page.tags="action bar","menu"
 parent.title=User Interface
 parent.link=index.html
 @jd:body
@@ -673,7 +674,7 @@
 view collapsible by adding {@code "collapseActionView"} to the {@code android:showAsAction}
 attribute, as shown in the XML above.</p>
 
-<p>Because the system will expand the action view when the user selects the item, so you
+<p>Because the system will expand the action view when the user selects the item, you
 <em>do not</em> need to respond to the item in the {@link
 android.app.Activity#onOptionsItemSelected onOptionsItemSelected} callback. The system still calls
 {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} when the user selects it,
diff --git a/docs/html/guide/topics/ui/binding.jd b/docs/html/guide/topics/ui/binding.jd
index e8b49d5..a4fd25c 100644
--- a/docs/html/guide/topics/ui/binding.jd
+++ b/docs/html/guide/topics/ui/binding.jd
@@ -10,13 +10,6 @@
     <li><a href="#FillingTheLayout">Filling the Layout with Data</a></li>
     <li><a href="#HandlingUserSelections">Handling User Selections</a></li>
   </ol>
-  
-  <h2>Related tutorials</h2>
-  <ol>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner</a></li>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-listview.html">List View</a></li>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Grid View</a></li>
-  </ol>
 </div>
 </div>
 
@@ -81,8 +74,8 @@
 </pre>
 
 <div class="special">
-<p>For more discussion on how to create different AdapterViews, read the following tutorials:
-<a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Hello Spinner</a>,
-<a href="{@docRoot}resources/tutorials/views/hello-listview.html">Hello ListView</a>, and
-<a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Hello GridView</a>.
+<p>For more discussion on how to create different AdapterViews, read the following guides:
+<a href="{@docRoot}guide/topics/ui/controls/spinner.html">Spinner</a>,
+<a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>, and
+<a href="{@docRoot}guide/topics/ui/layout/gridview.html">Grid View</a>.
 </div>
diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
index cacdf5c..884a1b2 100644
--- a/docs/html/guide/topics/ui/drag-drop.jd
+++ b/docs/html/guide/topics/ui/drag-drop.jd
@@ -750,7 +750,7 @@
         A{@link android.view.DragEvent#ACTION_DRAG_EXITED} event, it receives a new
         {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event every time the touch point moves.
         The {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} methods
-        return the the X and Y coordinates of the touch point.
+        return the X and Y coordinates of the touch point.
     </li>
     <li>
         {@link android.view.DragEvent#ACTION_DRAG_EXITED}:  This event is sent to a listener that
@@ -995,4 +995,4 @@
         };
     };
 };
-</pre>
\ No newline at end of file
+</pre>
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index 01d373e..dfcea52 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -834,7 +834,7 @@
 </ul>
 
 <p>You can create a group by nesting {@code &lt;item&gt;} elements inside a {@code &lt;group&gt;}
-element in your menu resource or by specifying a group ID with the the {@link
+element in your menu resource or by specifying a group ID with the {@link
 android.view.Menu#add(int,int,int,int) add()} method.</p>
 
 <p>Here's an example menu resource that includes a group:</p>
diff --git a/docs/html/guide/topics/ui/notifiers/toasts.jd b/docs/html/guide/topics/ui/notifiers/toasts.jd
index 92c146a..e5d4a0a 100644
--- a/docs/html/guide/topics/ui/notifiers/toasts.jd
+++ b/docs/html/guide/topics/ui/notifiers/toasts.jd
@@ -105,7 +105,7 @@
 &lt;/LinearLayout>
 </pre> 
 
-<p>Notice that the ID of the LinearLayout element is "toast_layout". You must use this
+<p>Notice that the ID of the LinearLayout element is "toast_layout_root". You must use this
 ID to inflate the layout from the XML, as shown here:</p>
 
 <pre>
diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd
index 707d4b1..6d41b15 100644
--- a/docs/html/guide/topics/ui/ui-events.jd
+++ b/docs/html/guide/topics/ui/ui-events.jd
@@ -13,10 +13,6 @@
     <li><a href="#HandlingFocus">Handling Focus</a></li>
   </ol>
 
-  <h2>Related tutorials</h2>
-  <ol>
-    <li><a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff</a></li>
-  </ol>
 </div>
 </div>
 
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index d2b2532..c87be06 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -33,11 +33,6 @@
   <li>{@link android.webkit.WebViewClient}</li>
 </ol>
 
-<h2>Related tutorials</h2>
-<ol>
-  <li><a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View</a></li>
-</ol>
-
 </div>
 </div>
 
diff --git a/docs/html/images/home/io-extended-2013.png b/docs/html/images/home/io-extended-2013.png
new file mode 100644
index 0000000..93989d4
--- /dev/null
+++ b/docs/html/images/home/io-extended-2013.png
Binary files differ
diff --git a/docs/html/images/home/io-logo-2013.png b/docs/html/images/home/io-logo-2013.png
index c95719e..1a200e1 100644
--- a/docs/html/images/home/io-logo-2013.png
+++ b/docs/html/images/home/io-logo-2013.png
Binary files differ
diff --git a/docs/html/images/ui/notifications/custom_message.png b/docs/html/images/ui/notifications/custom_message.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/images/ui/notifications/notifications_window.png b/docs/html/images/ui/notifications/notifications_window.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/images/ui/notifications/status_bar.png b/docs/html/images/ui/notifications/status_bar.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index a0029b5..29d6a8f 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -14,17 +14,16 @@
             <ul>
                 <li class="item carousel-home">
                     <div class="content-left col-10">
-                    <img src="{@docRoot}images/home/io-logo-2013.png" style="margin:40px 0 0">
+                    <img src="{@docRoot}images/home/io-extended-2013.png" style="margin:90px 0 0">
                     </div>
                     <div class="content-right col-5">
-                    <h1>Google I/O 2013</h1>
-                    <p>Android will be at Google I/O on May 15-17, 2013, with sessions covering a variety of topics
-                    such as design, performance, and how to extend your app with the latest Android features.
-                    Registration opens on March 13, 2013 at 7:00 AM PDT (GMT-7).</p>
-                    <p>For more information about event details and planned sessions,
-                    stay tuned to <a
-                    href="http://google.com/+GoogleDevelopers">+Google Developers</a>.</p>
-                    <p><a href="https://developers.google.com/events/io/" class="button">Register here</a></p>
+                    <h1>Google I/O Extended</h1>
+                    <p>Android will be at Google I/O on May 15-17, 2013, with sessions covering topics
+                    such as design, performance, and how to enhance your app with the latest Android features.</p>
+                    <p>Even if you can't make it there, you can experience the excitement and innovation of
+                    Google I/O remotely with Google I/O Extended.</p>
+                    <p><a href="https://developers.google.com/events/io/io-extended/?utm_source=site&utm_medium=emb&utm_campaign=extended-android-site"
+                    >Organize or attend an event near you &raquo;</a></p>
                     </div>
                 </li>
                 <li class="item carousel-home">
diff --git a/docs/html/tools/debugging/ddms.jd b/docs/html/tools/debugging/ddms.jd
index 3d6324b..f641aad 100644
--- a/docs/html/tools/debugging/ddms.jd
+++ b/docs/html/tools/debugging/ddms.jd
@@ -54,7 +54,7 @@
   <p>When DDMS starts, it connects to <a href="{@docRoot}tools/help/adb.html">adb</a>.
   When a device is connected, a VM monitoring service is created between
   <code>adb</code> and DDMS, which notifies DDMS when a VM on the device is started or terminated. Once a VM
-  is running, DDMS retrieves the the VM's process ID (pid), via <code>adb</code>, and opens a connection to the
+  is running, DDMS retrieves the VM's process ID (pid), via <code>adb</code>, and opens a connection to the
   VM's debugger, through the adb daemon (adbd) on the device. DDMS can now talk to the VM using a
   custom wire protocol.</p>
 
diff --git a/docs/html/tools/debugging/debugging-ui.jd b/docs/html/tools/debugging/debugging-ui.jd
index 8ca5192..f927d08 100644
--- a/docs/html/tools/debugging/debugging-ui.jd
+++ b/docs/html/tools/debugging/debugging-ui.jd
@@ -60,7 +60,9 @@
 
   <p>The Hierarchy Viewer application allows you to debug and optimize your user interface. It
   provides a visual representation of the layout's View hierarchy (the View Hierarchy window)
-  and a magnified view of the display (the Pixel Perfect window).</p>
+  with performance information for each node in the layout,
+  and a magnified view of the display (the Pixel Perfect window) to closely examine the pixels
+  in your layout.</p>
 
   <p>Android <code>lint</code> is a static code scanning tool that helps you optimize the layouts and layout
   hierarchies of your applications, as well as detect other common coding problems. You can run it against your layout files or resource
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index 9bdaf47..c7827b2 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -30,7 +30,7 @@
 you don't yet have a device, check with the service providers in your area to determine which
 Android-powered devices are available.</p>
 
-<p>If you want a SIM-unlocked phone, then you might consider the Google Nexus S. To find a place
+<p>If you want a SIM-unlocked phone, then you might consider a Nexus phone. To find a place
 to purchase the Nexus S and other Android-powered devices, visit <a
 href="http://www.google.com/phone/detail/nexus-s">google.com/phone</a>.</p>
 
diff --git a/docs/html/tools/devices/emulator.jd b/docs/html/tools/devices/emulator.jd
index cee6473..fda233d 100644
--- a/docs/html/tools/devices/emulator.jd
+++ b/docs/html/tools/devices/emulator.jd
@@ -898,7 +898,7 @@
 to/from that port to the emulated device's host port. </p>
 
 <p>To set up the network redirection, you create a mapping of host and guest
-ports/addresses on the the emulator instance. There are two ways to set up
+ports/addresses on the emulator instance. There are two ways to set up
 network redirection: using emulator console commands and using the ADB tool, as
 described below. </p>
 
@@ -1254,7 +1254,7 @@
 <td>&nbsp;</td>
 </tr>
 <tr>
-  <td><code>power health &lt;percent&gt;</code></td>
+  <td><code>capacity &lt;percent&gt;</code></td>
   <td>Set remaining battery capacity state (0-100).</td>
 <td>&nbsp;</td>
 </tr>
diff --git a/docs/html/tools/projects/index.jd b/docs/html/tools/projects/index.jd
index 6a49ac9..439d3be 100644
--- a/docs/html/tools/projects/index.jd
+++ b/docs/html/tools/projects/index.jd
@@ -68,12 +68,12 @@
     <code>src<em>/your/package/namespace/ActivityName</em>.java</code>. All other source code
      files (such as <code>.java</code> or <code>.aidl</code> files) go here as well.</dd>
 
-    <dt><code>bin</code></dt>
+    <dt><code>bin/</code></dt>
 
     <dd>Output directory of the build. This is where you can find the final <code>.apk</code> file and other
     compiled resources.</dd>
 
-    <dt><code>jni</code></dt>
+    <dt><code>jni/</code></dt>
 
     <dd>Contains native code sources developed using the Android NDK. For more information, see the
     <a href="{@docRoot}tools/sdk/ndk/index.html">Android NDK documentation</a>.</dd>
@@ -88,7 +88,7 @@
     <dd>This is empty. You can use it to store raw asset files. Files that you save here are
     compiled into an <code>.apk</code> file as-is, and the original filename is preserved. You can navigate this
     directory in the same way as a typical file system using URIs and read files as a stream of
-    bytes using the the {@link android.content.res.AssetManager}. For example, this is a good
+    bytes using the {@link android.content.res.AssetManager}. For example, this is a good
     location for textures and game data.</dd>
 
     <dt><code>res/</code></dt>
@@ -114,7 +114,7 @@
         <dt><code>drawable/</code></dt>
 
         <dd>For bitmap files (PNG, JPEG, or GIF), 9-Patch image files, and XML files that describe
-        Drawable shapes or a Drawable objects that contain multiple states (normal, pressed, or
+        Drawable shapes or Drawable objects that contain multiple states (normal, pressed, or
         focused). See the <a href=
         "{@docRoot}guide/topics/resources/drawable-resource.html">Drawable</a> resource type.</dd>
 
@@ -251,7 +251,7 @@
     code and resources as a standard Android project, stored in the same way. For example, source
     code in the library project can access its own resources through its <code>R</code> class.</p>
 
-    <p>However, a library project differs from an standard Android application project in that you
+    <p>However, a library project differs from a standard Android application project in that you
     cannot compile it directly to its own <code>.apk</code> and run it on an Android device.
     Similarly, you cannot export the library project to a self-contained JAR file, as you would do
     for a true library. Instead, you must compile the library indirectly, by referencing the
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index cb4954b..74caaf4 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -1,17 +1,29 @@
 ndk=true
 page.template=sdk
 
-ndk.win_download=android-ndk-r8d-windows.zip
-ndk.win_bytes=327014028
-ndk.win_checksum=d78ec3d4ec15ad3b18b9f488a5763c23
+ndk.mac64_download=android-ndk-r8e-darwin-x86_64.tar.bz2
+ndk.mac64_bytes=508419298
+ndk.mac64_checksum=efac96fab20e6ddb1311d6ba5648ce72
 
-ndk.mac_download=android-ndk-r8d-darwin-x86.tar.bz2
-ndk.mac_bytes=308328942
-ndk.mac_checksum=5cd9ef9fb7e03943ee8c9e147e42e571
+ndk.mac32_download=android-ndk-r8e-darwin-x86.tar.bz2
+ndk.mac32_bytes=496238878
+ndk.mac32_checksum=e17e707464c45c0d5615e4d0ae6a5cf7
 
-ndk.linux_download=android-ndk-r8d-linux-x86.tar.bz2
-ndk.linux_bytes=254644383
-ndk.linux_checksum=e1fa0379a3feb59f2f0865f1a90bd382
+ndk.linux64_download=android-ndk-r8e-linux-x86_64.tar.bz2
+ndk.linux64_bytes=466853553
+ndk.linux64_checksum=fa812352956067e7a9eefc0274675e9a
+
+ndk.linux32_download=android-ndk-r8e-linux-x86.tar.bz2
+ndk.linux32_bytes=461526099
+ndk.linux32_checksum=26d774b0884bcd98de08eb4de41ab532
+
+ndk.win64_download=android-ndk-r8e-windows-x86_64.zip
+ndk.win64_bytes=461298980
+ndk.win64_checksum=11eb99b3b56fc86d9d231ebff5c41db3
+
+ndk.win32_download=android-ndk-r8e-windows-x86.zip
+ndk.win32_bytes=434701805
+ndk.win32_checksum=fb41ed2bff5610b14a7b6f085ab86213
 
 page.title=Android NDK
 @jd:body
@@ -250,6 +262,222 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt="">Android NDK, Revision 8e</a> <em>(March 2013)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Important changes:</dt>
+      <dd>
+        <ul>
+          <li>Added 64-bit host toolchain set (package name suffix {@code *-x86_64.*}). For more
+            information, see {@code CHANGES.HTML} and {@code NDK-BUILD.html}.</li>
+          <li>Added Clang 3.2 compiler. GCC 4.6 is still the default. For information on using the
+            Clang compiler, see {@code CHANGES.HTML}.</li>
+          <li>Added static code analyzer for Linux/MacOSX hosts. For information on using the
+            analyzer, see {@code CHANGES.HTML}.</li>
+          <li>Added MCLinker for Linux/MacOSX hosts as an experimental feature. The {@code ld.gold}
+            linker is the default where available, so you must explicitly enable it. For more
+            information, see {@code CHANGES.HTML}.</li>
+          <li>Updated ndk-build to use topological sort for module dependencies, which means the
+            build automatically sorts out the order of libraries specified in
+            {@code LOCAL_STATIC_LIBRARIES}, {@code LOCAL_WHOLE_STATIC_LIBRARIES} and
+            {@code LOCAL_SHARED_LIBRARIES}. For more information, see {@code CHANGES.HTML}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39378">Issue 39378</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Important bug fixes:</dt>
+      <dd>
+        <ul>
+          <li>Fixed build script to build all toolchains in {@code -O2}. Toolchains in previous
+            releases were incorrectly built without optimization.</li>
+          <li>Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.</li>
+          <li>Fixed GCC 4.6/4.7 internal compiler error:
+            {@code gen_thumb_movhi_clobber at config/arm/arm.md:5832}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=52732">Issue 52732</a>)</li>
+          <li>Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic
+            built-in functions.
+            (<a href="http://code.google.com/p/android/issues/detail?id=41297">Issue 41297</a>)</li>
+          <li>Fixed GCC 4.7 linker DIV usage mismatch errors.
+          (<a href="http://sourceware.org/ml/binutils/2012-12/msg00202.html">Sourceware Issue</a>)
+          <li>Fixed GCC 4.7 internal compiler error {@code build_data_member_initialization, at
+            cp/semantics.c:5790}.</li>
+          <li>Fixed GCC 4.7 internal compiler error {@code redirect_eh_edge_1, at tree-eh.c:2214}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=52909">Issue 52909</a>)</li>
+          <li>Fixed a GCC 4.7 segfault.
+            (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55245">GCC Issue</a>)</li>
+          <li>Fixed {@code &lt;chrono&gt;} clock resolution and enabled {@code steady_clock}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39680">Issue 39680</a>)</li>
+          <li>Fixed toolchain to enable {@code _GLIBCXX_HAS_GTHREADS} for GCC 4.7 libstdc++.
+            (<a href="http://code.google.com/p/android/issues/detail?id=41770">Issue 41770</a>,
+             <a href="http://code.google.com/p/android/issues/detail?id=41859">Issue 41859</a>)</li>
+          <li>Fixed problem with the X86 MXX/SSE code failing to link due to missing
+            {@code posix_memalign}.
+            (<a href="https://android-review.googlesource.com/#/c/51872">Change 51872</a>)</li>
+          <li>Fixed GCC4.7/X86 segmentation fault in {@code i386.c}, function
+            {@code distance_non_agu_define_in_bb()}.
+            (<a href="https://android-review.googlesource.com/#/c/50383">Change 50383</a>)</li>
+          <li>Fixed GCC4.7/X86 to restore earlier {@code cmov} behavior.
+            (<a href="http://gcc.gnu.org/viewcvs?view=revision&revision=193554">GCC Issue</a>)</li>
+          <li>Fixed handling NULL return value of {@code setlocale()} in libstdc++/GCC4.7.
+            (<a href="http://code.google.com/p/android/issues/detail?id=46718">Issue 46718</a>)
+          <li>Fixed {@code ld.gold} runtime undefined reference to {@code __exidx_start} and
+            {@code __exidx_start_end}.
+            (<a href="https://android-review.googlesource.com/#/c/52134">Change 52134</a>)</li>
+          <li>Fixed Clang 3.1 internal compiler error when using Eigen library.
+            (<a href="http://code.google.com/p/android/issues/detail?id=41246">Issue 41246</a>)</li>
+          <li>Fixed Clang 3.1 internal compiler error including {@code &lt;chrono&gt;} in C++11 mode.
+            (<a href="http://code.google.com/p/android/issues/detail?id=39600">Issue 39600</a>)</li>
+          <li>Fixed Clang 3.1 internal compiler error when generating object code for a method
+            call to a uniform initialized {@code rvalue}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=41387">Issue 41387</a>)</li>
+          <li>Fixed Clang 3.1/X86 stack realignment.
+            (<a href="https://android-review.googlesource.com/#/c/52154">Change 52154</a>)</li>
+          <li>Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40941">Issue 40941</a>)</li>
+          <li>Fixed problem where GDB cannot set {@code source:line} breakpoints when symbols contain
+            long, indirect file paths.
+            (<a href="http://code.google.com/p/android/issues/detail?id=42448">Issue 42448</a>)</li>
+          <li>Fixed GDB {@code read_program_header} for MIPS PIE executables.
+            (<a href="https://android-review.googlesource.com/#/c/49592">Change 49592</a>)</li>
+          <li>Fixed {@code STLport} segmentation fault in {@code uncaught_exception()}.
+            (<a href="https://android-review.googlesource.com/#/c/50236">Change 50236</a>)</li>
+          <li>Fixed {@code STLport} bus error in exception handling due to unaligned access of
+            {@code DW_EH_PE_udata2}, {@code DW_EH_PE_udata4}, and {@code DW_EH_PE_udata8}.</li>
+          <li>Fixed Gabi++ infinite recursion problem with {@code nothrow new[]} operator.
+            (<a href="http://code.google.com/p/android/issues/detail?id=52833">Issue 52833</a>)</li>
+          <li>Fixed Gabi++ wrong offset to exception handler pointer.
+            (<a href="https://android-review.googlesource.com/#/c/53446">Change 53446</a>)</li>
+          <li>Removed Gabi++ redundant free on exception object
+            (<a href="https://android-review.googlesource.com/#/c/53447">Change 53447</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Other bug fixes:</dt>
+      <dd>
+        <ul>
+          <li>Fixed NDK headers:
+            <ul>
+              <li>Removed redundant definitions of {@code size_t}, {@code ssize_t}, and
+                {@code ptrdiff_t}.</li>
+              <li>Fixed MIPS and ARM {@code fenv.h} header.</li>
+              <li>Fixed {@code stddef.h} to not redefine {@code offsetof} since it already exists
+                in the toolchain.</li>
+              <li>Fixed {@code elf.h} to contain {@code Elf32_auxv_t} and {@code Elf64_auxv_t}.
+                (<a href="http://code.google.com/p/android/issues/detail?id=38441">Issue 38441</a>)
+                </li>
+              <li>Fixed the {@code #ifdef} C++ definitions in the
+                {@code OpenSLES_AndroidConfiguration.h} header file.
+                (<a href="http://code.google.com/p/android/issues/detail?id=53163">Issue 53163</a>)
+                </li>
+            </ul>
+          </li>
+          <li>Fixed {@code STLport} to abort after out of memory error instead of silently exiting.
+            </li>
+          <li>Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.</li>
+          <li>Fixed {@code cpufeatures} to not parse {@code /proc/self/auxv}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=43055">Issue 43055</a>)</li>
+          <li>Fixed {@code ld.gold} to not depend on host libstdc++ and on Windows platforms,
+            to not depend on the {@code libgcc_sjlj_1.dll} library.</li>
+          <li>Fixed Clang 3.1 which emits inconsistent register list in {@code .vsave} and fails
+            assembler.
+            (<a href="https://android-review.googlesource.com/#/c/49930">Change 49930</a>)</li>
+          <li>Fixed Clang 3.1 to be able to compile libgabi++ and pass the {@code test-stlport}
+            tests for MIPS build targets.
+            (<a href="https://android-review.googlesource.com/#/c/51961">Change 51961</a>)</li>
+          <li>Fixed Clang 3.1 to only enable exception by default for C++, not for C.</li>
+          <li>Fixed several issues in Clang 3.1 to pass most GNU exception tests.</li>
+          <li>Fixed scripts {@code clang} and {@code clang++} in standalone NDK compiler to detect
+            {@code -cc1} and to not specify {@code -target} when found.</li>
+          <li>Fixed {@code ndk-build} to observe {@code NDK_APP_OUT} set in {@code Application.mk}.
+            </li>
+          <li>Fixed X86 {@code libc.so} and {@code lib.a} which were missing the {@code sigsetjmp}
+            and {@code siglongjmp} functions already declared in {@code setjmp.h}.
+            (<a href="http://code.google.com/p/android/issues/detail?id=19851">Issue 19851</a>)</li>
+          <li>Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11.
+            (<a href="http://clang.llvm.org/cxx_status.html">Clang Issue</a>)</li>
+          <li>Fixed cygwin path in argument passed to {@code HOST_AWK}.</li>
+          <li>Fixed {@code ndk-build} script warning in windows when running from project's JNI
+            directory.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40192">Issue 40192</a>)</li>
+          <li>Fixed problem where the {@code ndk-build} script does not build if makefile has
+            trailing whitespace in the {@code LOCAL_PATH} definition.
+            (<a href="http://code.google.com/p/android/issues/detail?id=42841">Issue 42841</a>)</li>
+        </ul>
+      </dd>
+
+      <dt>Other changes:</dt>
+      <dd>
+        <ul>
+          <li>Enabled threading support in GCC/MIPS toolchain.</li>
+          <li>Updated GCC exception handling helpers {@code __cxa_begin_cleanup} and
+            {@code __cxa_type_match} to have <em>default</em> visibility from the previous
+            <em>hidden</em> visibility in GNU libstdc++. For more information, see
+            {@code CHANGES.HTML}.</li>
+          <li>Updated build scripts so that Gabi++ and STLport static libraries are now built with
+            hidden visibility except for exception handling helpers.</li>
+          <li>Updated build so that {@code STLport} is built for ARM in Thumb mode.</li>
+          <li>Added support for {@code std::set_new_handler} in Gabi++.
+            (<a href="http://code.google.com/p/android/issues/detail?id=52805">Issue 52805</a>)</li>
+          <li>Enabled {@code FUTEX} system call in GNU libstdc++.</li>
+          <li>Updated {@code ndk-build} so that it  no longer copies prebuilt static library to
+            a project's {@code obj/local/&lt;abi&gt;/} directory.
+            (<a href="http://code.google.com/p/android/issues/detail?id=40302">Issue 40302</a>)</li>
+          <li>Removed {@code __ARM_ARCH_5*__} from ARM {@code toolchains/*/setup.mk} script.
+            (<a href="http://code.google.com/p/android/issues/detail?id=21132">Issue 21132</a>)</li>
+          <li>Built additional GNU libstdc++ libraries in thumb for ARM.</li>
+          <li>Enabled MIPS floating-point {@code madd/msub/nmadd/nmsub/recip/rsqrt}
+            instructions with 32-bit FPU.</li>
+          <li>Enabled graphite loop optimizer in GCC 4.6 and 4.7 to allow more optimizations:
+            {@code -fgraphite}, {@code -fgraphite-identity}, {@code -floop-block}, {@code -floop-flatten},
+            {@code -floop-interchange}, {@code -floop-strip-mine}, {@code -floop-parallelize-all},
+            and {@code -ftree-loop-linear}.
+            (<a href="http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html">info</a>)</li>
+          <li>Enabled {@code polly} for Clang 3.1 on Linux and Max OS X 32-bit hosts which analyzes
+            and optimizes memory access. (<a href="http://polly.llvm.org">info</a>)</li>
+          <li>Enabled {@code -flto} in GCC 4.7, 4.6, Clang 3.2 and Clang 3.1 on linux (Clang LTO
+            via LLVMgold.so). MIPS compiler targets are not supported because {@code ld.gold}
+            is not available.</li>
+          <li>Enabled {@code --plugin} and {@code --plugin-opt} for {@code ld.gold} in GCC 4.6/4.7.
+            </li>
+          <li>Enabled {@code --text-reorder} for {@code ld.gold} in GCC 4.7.</li>
+          <li>Configured GNU libstdc++ with {@code _GLIBCXX_USE_C99_MATH} which undefines the
+            {@code isinf} script in the bionic header. For more information, see
+            {@code CHANGES.html}.</li>
+          <li>Added {@code APP_LDFLAGS} to the build scripts. For more information, see
+            {@code ANDROID-MK.html}.</li>
+          <li>Updated build scripts to allow {@code NDK_LOG=0} to disable the {@code NDK_LOG}.</li>
+          <li>Updated build scripts to allow {@code NDK_HOST_32BIT=0} to disable the host developer
+            environment 32-bit toolchain.</li>
+          <li>Changed the default GCC/X86 flags {@code -march=} and {@code -mtune=} from
+            {@code pentiumpro} and {@code generic} to {@code i686} and {@code atom}.</li>
+          <li>Enhanced toolchain build scripts:
+            <ul>
+              <li>Fixed a race condition in {@code build-gcc.sh} for the {@code mingw} build type
+                which was preventing a significant amount of parallel build processing.</li>
+              <li>Updated {@code build-gabi++.sh} and {@code build-stlport.sh} so they can now run
+                from the NDK package.
+                (<a href="http://code.google.com/p/android/issues/detail?id=52835">Issue 52835</a>)
+                </li>
+              <li>Fixed {@code run-tests.sh} in the {@code MSys} utilities collection.</li>
+              <li>Improved 64-bit host toolchain and Canadian Cross build support.</li>
+              <li>Updated {@code build-mingw64-toolchain.sh} script to more recent version.</li>
+              <li>Added option to build {@code libgnustl_static.a} and {@code stlport_static.a}
+                without hidden visibility.</li>
+            </ul>
+          </li>
+        </ul>
+
+      </dd>
+    </dl>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt="">Android NDK, Revision 8d</a> <em>(December 2012)</em>
   </p>
 
@@ -769,7 +997,7 @@
       <dd>
         <ul>
           <li>Added GCC 4.6 toolchain ({@code binutils} 2.21 with {@code gold} and GDB 7.3.x) to
-co-exist with the original GCC 4.4.3 toolchain ({@code binutils} 2.19 and GDB 6.6).</p>
+co-exist with the original GCC 4.4.3 toolchain ({@code binutils} 2.19 and GDB 6.6).
             <ul>
               <li>GCC 4.6 is now the default toolchain. You may set {@code
 NDK_TOOLCHAIN_VERSION=4.4.3} in {@code Application.mk} to select the original one.</li>
@@ -816,8 +1044,9 @@
 following options:
 <pre>
 LOCAL_DISABLE_NO_EXECUTE=true  # disable "--noexecstack" and "-z noexecstack"
-DISABLE_RELRO=true             # disable "-z relro" and "-z now"</li>
+DISABLE_RELRO=true             # disable "-z relro" and "-z now"
 </pre>
+                  </li>
                 </ol>
                 <p>See {@code docs/ANDROID-MK.html} for more details.</p>
               </li>
@@ -826,7 +1055,7 @@
 
           <li>Added branding for Android executables with the {@code .note.ABI-tag} section (in
 {@code crtbegin_static/dynamic.o}) so that debugging tools can act accordingly. The structure
-member and values are defined as follows:</p>
+member and values are defined as follows:
 <pre>
 static const struct {
   int32_t namesz;  /* = 4,  sizeof ("GNU") */
@@ -1621,10 +1850,11 @@
           <li>Fixed a bug that caused the build to fail if <code>LOCAL_ARM_NEON</code> was set to
           true (typo in <code>build/core/build-binary.mk</code>).</li>
 
-          <li>Fixed a bug that prevented the compilation of </code>.s</code> assembly files
+          <li>Fixed a bug that prevented the compilation of <code>.s</code> assembly files
           (<code>.S</code> files were okay).</li>
         </ul>
       </dd>
+    </dl>
   </div>
 </div>
 
diff --git a/docs/html/tools/testing/activity_test.jd b/docs/html/tools/testing/activity_test.jd
index 8288249..096aea5 100644
--- a/docs/html/tools/testing/activity_test.jd
+++ b/docs/html/tools/testing/activity_test.jd
@@ -537,7 +537,7 @@
 import android.widget.SpinnerAdapter;
 </pre>
 <p>
-    You now have the the complete <code>setUp()</code> method.
+    You now have the complete <code>setUp()</code> method.
 </p>
 <h3 id="AddPreConditionsTest">Adding an initial conditions test</h3>
 <p>
@@ -1266,7 +1266,7 @@
   </li>
   <li>
     Follow the tutorial, starting with the section <a href="#CreateTestCaseClass">Creating the Test Case Class</a>. When you are prompted to
-    run the sample application, go the the Launcher screen in your device or emulator and select SpinnerActivity.
+    run the sample application, go to the Launcher screen in your device or emulator and select SpinnerActivity.
     When you are prompted to run the test application, return here to continue with the following instructions.
   </li>
   <li>
diff --git a/docs/html/tools/testing/activity_testing.jd b/docs/html/tools/testing/activity_testing.jd
index 7190b98..88ac9b2 100644
--- a/docs/html/tools/testing/activity_testing.jd
+++ b/docs/html/tools/testing/activity_testing.jd
@@ -77,7 +77,7 @@
   </div>
 </div>
 <p>
-    Activity testing is particularly dependent on the the Android instrumentation framework.
+    Activity testing is particularly dependent on the Android instrumentation framework.
     Unlike other components, activities have a complex lifecycle based on callback methods; these
     can't be invoked directly except by instrumentation. Also, the only way to send events to the
     user interface from a program is through instrumentation.
@@ -322,7 +322,7 @@
     the published application.
 </p>
 <p>
-    To add the the permission, add the element
+    To add the permission, add the element
     <code>&lt;uses-permission android:name="android.permission.DISABLE_KEYGUARD"/&gt;</code>
     as a child of the <code>&lt;manifest&gt;</code> element. To disable the KeyGuard, add the
     following code to the <code>onCreate()</code> method of activities you intend to test:
diff --git a/docs/html/tools/testing/testing_android.jd b/docs/html/tools/testing/testing_android.jd
index acf5ec2..10843e8 100644
--- a/docs/html/tools/testing/testing_android.jd
+++ b/docs/html/tools/testing/testing_android.jd
@@ -111,14 +111,14 @@
     </li>
     <li>
         The SDK tools for building and tests are available in Eclipse with ADT, and also in
-        command-line form for use with other IDES. These tools get information from the project of
+        command-line form for use with other IDEs. These tools get information from the project of
         the application under test and use this information to automatically create the build files,
         manifest file, and directory structure for the test package.
     </li>
     <li>
         The SDK also provides
   <a href="{@docRoot}tools/help/monkeyrunner_concepts.html">monkeyrunner</a>, an API
-        testing devices with Python programs, and <a
+        for testing devices with Python programs, and <a
         href="{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a>,
         a command-line tool for stress-testing UIs by sending pseudo-random events to a device.
     </li>
diff --git a/docs/html/tools/testing/testing_otheride.jd b/docs/html/tools/testing/testing_otheride.jd
index 0678f52..9484158 100644
--- a/docs/html/tools/testing/testing_otheride.jd
+++ b/docs/html/tools/testing/testing_otheride.jd
@@ -75,9 +75,9 @@
 <p>
     You use the <code>android</code> tool to create test projects.
     You also use <code>android</code> to convert existing test code into an Android test project,
-    or to add the <code>run-tests</code> Ant target to an existing Android test project.
+    or to add the <code>test</code> Ant target to an existing Android test project.
     These operations are described in more detail in the section <a href="#UpdateTestProject">
-    Updating a test project</a>. The <code>run-tests</code> target is described in
+    Updating a test project</a>. The <code>test</code> target is described in
     <a href="#RunTestsAnt">Quick build and run with Ant</a>.
 </p>
 <h3 id="CreateTestProject">Creating a test project</h3>
@@ -300,7 +300,7 @@
 <h3 id="RunTestsAnt">Quick build and run with Ant</h3>
 <p>
     You can use Ant to run all the tests in your test project, using the target
-    <code>run-tests</code>, which is created automatically when you create a test project with
+    <code>test</code>, which is created automatically when you create a test project with
     the <code>android</code> tool.
 </p>
 <p>
diff --git a/docs/html/tools/workflow/index.jd b/docs/html/tools/workflow/index.jd
index 5ae06e6..784b212 100644
--- a/docs/html/tools/workflow/index.jd
+++ b/docs/html/tools/workflow/index.jd
@@ -34,7 +34,7 @@
   </li>
   <li><strong>Development</strong>
     <p>During this phase you set up and develop your Android project, which contains all of the
-    source code and resource files for your application. For more informations, see
+    source code and resource files for your application. For more information, see
     <a href="{@docRoot}tools/projects/index.html">Create an Android project</a>.</p>
   </li>
   <li><strong>Debugging and Testing</strong>
diff --git a/docs/html/training/accessibility/service.jd b/docs/html/training/accessibility/service.jd
index 373ddbb..953c558 100644
--- a/docs/html/training/accessibility/service.jd
+++ b/docs/html/training/accessibility/service.jd
@@ -204,7 +204,7 @@
 <p>This step is optional, but highly useful.  One of the new features in Android
 4.0 (API Level 14) is the ability for an
 {@link android.accessibilityservice.AccessibilityService} to query the view
-hierarchy, collecting information about the the UI component that generated an event, and
+hierarchy, collecting information about the UI component that generated an event, and
 its parent and children.  In order to do this, make sure that you set the
 following line in your XML configuration:</p>
 <pre>
diff --git a/docs/html/training/animation/anim_card_flip.mp4 b/docs/html/training/animation/anim_card_flip.mp4
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/training/animation/anim_card_flip.ogv b/docs/html/training/animation/anim_card_flip.ogv
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/training/animation/anim_card_flip.webm b/docs/html/training/animation/anim_card_flip.webm
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/training/animation/anim_screenslide.mp4 b/docs/html/training/animation/anim_screenslide.mp4
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/training/animation/anim_screenslide.ogv b/docs/html/training/animation/anim_screenslide.ogv
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/training/animation/anim_screenslide.webm b/docs/html/training/animation/anim_screenslide.webm
old mode 100755
new mode 100644
Binary files differ
diff --git a/docs/html/training/animation/cardflip.jd b/docs/html/training/animation/cardflip.jd
index 1477f9fa..48fbbd8 100644
--- a/docs/html/training/animation/cardflip.jd
+++ b/docs/html/training/animation/cardflip.jd
@@ -70,7 +70,7 @@
         <code>animator/card_flip_right_out.xml</code>
       </li>
       <li>
-        <code>animator/card_flip_right_in.xml</code>
+        <code>animator/card_flip_left_in.xml</code>
       </li>
       <li>
         <code>animator/card_flip_left_out.xml</code>
@@ -372,4 +372,4 @@
             // Commit the transaction.
             .commit();
 }
-</pre>
\ No newline at end of file
+</pre>
diff --git a/docs/html/training/animation/index.jd b/docs/html/training/animation/index.jd
index 9cc7e6c..b2815fc 100644
--- a/docs/html/training/animation/index.jd
+++ b/docs/html/training/animation/index.jd
@@ -1,4 +1,5 @@
 page.title=Adding Animations
+page.tags="animation","views","layout","user interface"
 trainingnavtop=true
 startpage=true
 
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
index 8b11983..61fb758 100644
--- a/docs/html/training/basics/data-storage/databases.jd
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -1,6 +1,4 @@
 page.title=Saving Data in SQL Databases
-parent.title=Data Storage
-parent.link=index.html
 
 trainingnavtop=true
 previous.title=Saving Data in Files
@@ -286,7 +284,7 @@
 // Define 'where' part of query.
 String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
 // Specify arguments in placeholder order.
-String[] selelectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { String.valueOf(rowId) };
 // Issue SQL statement.
 db.delete(table_name, selection, selectionArgs);
 </pre>
@@ -311,7 +309,7 @@
 
 // Which row to update, based on the ID
 String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
-String[] selelectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { String.valueOf(rowId) };
 
 int count = db.update(
     FeedReaderDbHelper.FeedEntry.TABLE_NAME,
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index dd081a6..52bea4c 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -1,6 +1,4 @@
 page.title=Saving Files
-parent.title=Data Storage
-parent.link=index.html
 
 trainingnavtop=true
 
diff --git a/docs/html/training/basics/data-storage/index.jd b/docs/html/training/basics/data-storage/index.jd
index 4334936..4ccad75 100644
--- a/docs/html/training/basics/data-storage/index.jd
+++ b/docs/html/training/basics/data-storage/index.jd
@@ -1,4 +1,5 @@
 page.title=Saving Data
+page.tags="data storage","files","sql","database","preferences"
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/data-storage/shared-preferences.jd b/docs/html/training/basics/data-storage/shared-preferences.jd
index 099da67..a6717c4 100644
--- a/docs/html/training/basics/data-storage/shared-preferences.jd
+++ b/docs/html/training/basics/data-storage/shared-preferences.jd
@@ -1,6 +1,4 @@
 page.title=Saving Key-Value Sets
-parent.title=Data Storage
-parent.link=index.html
 
 trainingnavtop=true
 
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
index 0f18861..2615bee 100644
--- a/docs/html/training/basics/firstapp/building-ui.jd
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -240,7 +240,7 @@
     &lt;string name="app_name">My First App&lt;/string>
     &lt;string name="edit_message">Enter a message&lt;/string>
     &lt;string name="button_send">Send&lt;/string>
-    &lt;string name="menu_settings">Settings&lt;/string>
+    &lt;string name="action_settings">Settings&lt;/string>
     &lt;string name="title_activity_main">MainActivity&lt;/string>
 &lt;/resources>
 </pre>
diff --git a/docs/html/training/basics/fragments/communicating.jd b/docs/html/training/basics/fragments/communicating.jd
index eb9b368..b30045d 100644
--- a/docs/html/training/basics/fragments/communicating.jd
+++ b/docs/html/training/basics/fragments/communicating.jd
@@ -1,10 +1,6 @@
 page.title=Communicating with Other Fragments
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
 
 trainingnavtop=true
-previous.title=Building a Flexible UI
-previous.link=fragment-ui.html
 
 @jd:body
 
diff --git a/docs/html/training/basics/fragments/creating.jd b/docs/html/training/basics/fragments/creating.jd
index 0646230..b5df4e1 100644
--- a/docs/html/training/basics/fragments/creating.jd
+++ b/docs/html/training/basics/fragments/creating.jd
@@ -1,12 +1,6 @@
 page.title=Creating a Fragment
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
 
 trainingnavtop=true
-previous.title=Using the Android Support Library
-previous.link=support-lib.html
-next.title=Building a Flexible UI
-next.link=fragment-ui.html
 
 @jd:body
 
diff --git a/docs/html/training/basics/fragments/fragment-ui.jd b/docs/html/training/basics/fragments/fragment-ui.jd
index 4ec4de5..db3119b 100644
--- a/docs/html/training/basics/fragments/fragment-ui.jd
+++ b/docs/html/training/basics/fragments/fragment-ui.jd
@@ -1,12 +1,6 @@
 page.title=Building a Flexible UI
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
 
 trainingnavtop=true
-previous.title=Create a Fragment
-previous.link=creating.html
-next.title=Communicating with Other Fragments
-next.link=communicating.html
 
 @jd:body
 
@@ -47,7 +41,7 @@
 
 <img src="{@docRoot}images/training/basics/fragments-screen-mock.png" alt="" />
 <p class="img-caption"><strong>Figure 1.</strong> Two fragments, displayed in different
-configurations for the same activity on different screen sizes. On a large screen, both fragment
+configurations for the same activity on different screen sizes. On a large screen, both fragments
 fit side by side, but on a handset device, only one fragment fits at a time so the fragments must
 replace each other as the user navigates.</p>
 
diff --git a/docs/html/training/basics/fragments/index.jd b/docs/html/training/basics/fragments/index.jd
index bc93f43..1b82f2c 100644
--- a/docs/html/training/basics/fragments/index.jd
+++ b/docs/html/training/basics/fragments/index.jd
@@ -1,9 +1,8 @@
 page.title=Building a Dynamic UI with Fragments
+page.tags="fragments", "user interface", "support library"
 
 trainingnavtop=true
 startpage=true
-next.title=Using the Android Support Library
-next.link=support-lib.html
 
 @jd:body
 
diff --git a/docs/html/training/basics/fragments/support-lib.jd b/docs/html/training/basics/fragments/support-lib.jd
index cc867d3..b097de1 100644
--- a/docs/html/training/basics/fragments/support-lib.jd
+++ b/docs/html/training/basics/fragments/support-lib.jd
@@ -1,10 +1,7 @@
 page.title=Using the Support Library
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
+page.tags="support library"
 
 trainingnavtop=true
-next.title=Creating a Fragment
-next.link=creating.html
 
 @jd:body
 
diff --git a/docs/html/training/basics/intents/index.jd b/docs/html/training/basics/intents/index.jd
index d94ff015..8876a33 100644
--- a/docs/html/training/basics/intents/index.jd
+++ b/docs/html/training/basics/intents/index.jd
@@ -1,9 +1,8 @@
 page.title=Interacting with Other Apps
+page.tags="intents","activity"
 
 trainingnavtop=true
 startpage=true
-next.title=Sending the User to Another App
-next.link=sending.html
 
 @jd:body
 
diff --git a/docs/html/training/basics/intents/result.jd b/docs/html/training/basics/intents/result.jd
index 0086913..24ecc46 100644
--- a/docs/html/training/basics/intents/result.jd
+++ b/docs/html/training/basics/intents/result.jd
@@ -62,7 +62,7 @@
 static final int PICK_CONTACT_REQUEST = 1;  // The request code
 ...
 private void pickContact() {
-    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
+    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
     pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
     startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
 }
diff --git a/docs/html/training/basics/network-ops/connecting.jd b/docs/html/training/basics/network-ops/connecting.jd
index ac8d993..50a9e1b 100644
--- a/docs/html/training/basics/network-ops/connecting.jd
+++ b/docs/html/training/basics/network-ops/connecting.jd
@@ -136,7 +136,7 @@
             getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
         if (networkInfo != null &amp;&amp; networkInfo.isConnected()) {
-            new DownloadWebpageText().execute(stringUrl);
+            new DownloadWebpageTask().execute(stringUrl);
         } else {
             textView.setText("No network connection available.");
         }
@@ -147,7 +147,7 @@
      // has been established, the AsyncTask downloads the contents of the webpage as
      // an InputStream. Finally, the InputStream is converted into a string, which is
      // displayed in the UI by the AsyncTask's onPostExecute method.
-     private class DownloadWebpageText extends AsyncTask<String, Void, String> {
+     private class DownloadWebpageTask extends AsyncTask&lt;String, Void, String&gt; {
         &#64;Override
         protected String doInBackground(String... urls) {
               
diff --git a/docs/html/training/basics/network-ops/index.jd b/docs/html/training/basics/network-ops/index.jd
index b213c03..cb3a390 100644
--- a/docs/html/training/basics/network-ops/index.jd
+++ b/docs/html/training/basics/network-ops/index.jd
@@ -1,4 +1,5 @@
 page.title=Performing Network Operations
+page.tags="network","wireless"
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/network-ops/managing.jd b/docs/html/training/basics/network-ops/managing.jd
index 0f3d495..990b8cb 100644
--- a/docs/html/training/basics/network-ops/managing.jd
+++ b/docs/html/training/basics/network-ops/managing.jd
@@ -269,7 +269,7 @@
   
     // When the user changes the preferences selection, 
     // onSharedPreferenceChanged() restarts the main activity as a new
-    // task. Sets the the refreshDisplay flag to "true" to indicate that 
+    // task. Sets the refreshDisplay flag to "true" to indicate that
     // the main activity should update its display.
     // The main activity queries the PreferenceManager to get the latest settings.
     
diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd
index 49ea81d..1e3eb42 100644
--- a/docs/html/training/basics/supporting-devices/index.jd
+++ b/docs/html/training/basics/supporting-devices/index.jd
@@ -1,9 +1,8 @@
 page.title=Supporting Different Devices
+page.tags="resources","screens","versions","localization"
 
 trainingnavtop=true
 startpage=true
-next.title=Supporting Multiple Languages
-next.link=languages.html
 
 @jd:body
 
diff --git a/docs/html/training/camera/index.jd b/docs/html/training/camera/index.jd
index 282bed8..fa754a0 100644
--- a/docs/html/training/camera/index.jd
+++ b/docs/html/training/camera/index.jd
@@ -1,4 +1,5 @@
 page.title=Capturing Photos
+page.tags="camera","video"
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index 91885e8..55b275b 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -1,9 +1,8 @@
 page.title=Syncing to the Cloud
+page.tags="cloud","sync","backup"
 
 trainingnavtop=true
 startpage=true
-next.title=Making the Most of Google Cloud Messaging
-next.link=gcm.html
 
 @jd:body
 
diff --git a/docs/html/training/connect-devices-wirelessly/index.jd b/docs/html/training/connect-devices-wirelessly/index.jd
index 37cf633..f27b9c3 100644
--- a/docs/html/training/connect-devices-wirelessly/index.jd
+++ b/docs/html/training/connect-devices-wirelessly/index.jd
@@ -1,9 +1,8 @@
 page.title=Connecting Devices Wirelessly
+page.tags="wifi","network","wireless"
 
 trainingnavtop=true
 startpage=true
-next.title=Using Network Service Discovery
-next.link=nsd.html
 
 @jd:body
 
diff --git a/docs/html/training/contacts-provider/ContactsList.zip b/docs/html/training/contacts-provider/ContactsList.zip
new file mode 100644
index 0000000..d2a5cfb
--- /dev/null
+++ b/docs/html/training/contacts-provider/ContactsList.zip
Binary files differ
diff --git a/docs/html/training/contacts-provider/display-contact-badge.jd b/docs/html/training/contacts-provider/display-contact-badge.jd
new file mode 100644
index 0000000..f08935d
--- /dev/null
+++ b/docs/html/training/contacts-provider/display-contact-badge.jd
@@ -0,0 +1,635 @@
+page.title=Displaying the Quick Contact Badge
+
+trainingnavtop=true
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+    <li>
+        <a href="#AddView">Add a QuickContactBadge View</a>
+    </li>
+    <li>
+        <a href="#SetURIThumbnail">Set the Contact URI and Thumbnail</a>
+    </li>
+    <li>
+        <a href="#ListView">
+            Add a QuickContactBadge to a ListView
+        </a>
+    </li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics
+        </a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+        Contacts Provider
+        </a>
+    </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+    <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+    Download the sample
+    </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    This lesson shows you how to add a {@link android.widget.QuickContactBadge} to your UI
+    and how to bind data to it. A {@link android.widget.QuickContactBadge} is a widget that
+    initially appears as a thumbnail image. Although you can use any {@link android.graphics.Bitmap}
+    for the thumbnail image, you usually use a {@link android.graphics.Bitmap} decoded from the
+    contact's photo thumbnail image.
+</p>
+<p>
+    The small image acts as a control; when users click on the image, the
+    {@link android.widget.QuickContactBadge} expands into a dialog containing the following:
+</p>
+<dl>
+    <dt>A large image</dt>
+    <dd>
+        The large image associated with the contact, or no image is available, a placeholder
+        graphic.
+    </dd>
+    <dt>
+        App icons
+    </dt>
+    <dd>
+        An app icon for each piece of detail data that can be handled by a built-in app. For
+        example, if the contact's details include one or more email addresses, an email icon
+        appears. When users click the icon, all of the contact's email addresses appear. When users
+        click one of the addresses, the email app displays a screen for composing a message to the
+        selected email address.
+    </dd>
+</dl>
+<p>
+    The {@link android.widget.QuickContactBadge} view provides instant access to a contact's
+    details, as well as a fast way of communicating with the contact. Users don't have to look up
+    a contact, find and copy information, and then paste it into the appropriate app. Instead, they
+    can click on the {@link android.widget.QuickContactBadge}, choose the communication method they
+    want to use, and send the information for that method directly to the appropriate app.
+</p>
+<h2 id="AddView">Add a QuickContactBadge View</h2>
+<p>
+    To add a {@link android.widget.QuickContactBadge}, insert a
+    <code>&lt;QuickContactBadge&gt;</code> element in your layout. For example:
+</p>
+<pre>
+&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"&gt;
+...
+    &lt;QuickContactBadge
+               android:id=&#64;+id/quickbadge
+               android:layout_height="wrap_content"
+               android:layout_width="wrap_content"
+               android:scaleType="centerCrop"/&gt;
+    ...
+&lt;/RelativeLayout&gt;
+</pre>
+<h2 id="">Retrieve provider data</h2>
+<p>
+    To display a contact in the {@link android.widget.QuickContactBadge}, you need a content URI
+    for the contact and a {@link android.graphics.Bitmap} for the small image. You generate
+    both the content URI and the {@link android.graphics.Bitmap} from columns retrieved from the
+    Contacts Provider. Specify these columns as part of the projection you use to load data into
+    your {@link android.database.Cursor}.
+</p>
+<p>
+    For Android 3.0 (API level 11) and later, include the following columns in your projection:</p>
+<ul>
+    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
+    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
+    <li>
+        {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI
+        Contacts.PHOTO_THUMBNAIL_URI}
+    </li>
+</ul>
+<p>
+    For Android 2.3.3 (API level 10) and earlier, use the following columns:
+</p>
+<ul>
+    <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
+    <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
+</ul>
+<p>
+    The remainder of this lesson assumes that you've already loaded a
+    {@link android.database.Cursor} that contains these columns as well as others you may have
+    chosen. To learn how to retrieve this columns in a {@link android.database.Cursor}, read the
+    lesson <a href="retrieve-names.html">Retrieving a List of Contacts</a>.
+</p>
+<h2 id="SetURIThumbnail">Set the Contact URI and Thumbnail</h2>
+<p>
+    Once you have the necessary columns, you can bind data to the
+    {@link android.widget.QuickContactBadge}.
+</p>
+<h3>Set the Contact URI</h3>
+<p>
+    To set the content URI for the contact, call
+    {@link android.provider.ContactsContract.Contacts#getLookupUri getLookupUri(id,lookupKey)} to
+    get a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, then
+    call {@link android.widget.QuickContactBadge#assignContactUri assignContactUri()} to set the
+    contact. For example:
+</p>
+<pre>
+    // The Cursor that contains contact rows
+    Cursor mCursor;
+    // The index of the _ID column in the Cursor
+    int mIdColumn;
+    // The index of the LOOKUP_KEY column in the Cursor
+    int mLookupKeyColumn;
+    // A content URI for the desired contact
+    Uri mContactUri;
+    // A handle to the QuickContactBadge view
+    QuickContactBadge mBadge;
+    ...
+    mBadge = (QuickContactBadge) findViewById(R.id.quickbadge);
+    /*
+     * Insert code here to move to the desired cursor row
+     */
+    // Gets the _ID column index
+    mIdColumn = mCursor.getColumnIndex(Contacts._ID);
+    // Gets the LOOKUP_KEY index
+    mLookupKeyColumn = mCursor.getColumnIndex(Contacts.LOOKUP_KEY);
+    // Gets a content URI for the contact
+    mContactUri =
+            Contacts.getLookupUri(
+                Cursor.getLong(mIdColumn),
+                Cursor.getString(mLookupKeyColumn)
+            );
+    mBadge.assignContactUri(mContactUri);
+</pre>
+<p>
+    When users click the {@link android.widget.QuickContactBadge} icon, the contact's
+    details automatically appear in the dialog.
+</p>
+<h3>Set the photo thumbnail</h3>
+<p>
+    Setting the contact URI for the {@link android.widget.QuickContactBadge} does not automatically
+    load the contact's thumbnail photo. To load the photo, get a URI for the photo from the
+    contact's {@link android.database.Cursor} row, use it to open the file containing the compressed
+    thumbnail photo, and read the file into a {@link android.graphics.Bitmap}.
+</p>
+<p class="note">
+    <strong>Note:</strong> The
+    {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI} column isn't available
+    in platform versions prior to 3.0. For those versions, you must retrieve the URI
+    from the {@link android.provider.ContactsContract.Contacts.Photo Contacts.Photo} subtable.
+</p>
+<p>
+    First, set up variables for accessing the {@link android.database.Cursor} containing the
+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
+    described previously:
+</p>
+<pre>
+    // The column in which to find the thumbnail ID
+    int mThumbnailColumn;
+    /*
+     * The thumbnail URI, expressed as a String.
+     * Contacts Provider stores URIs as String values.
+     */
+    String mThumbnailUri;
+    ...
+    /*
+     * Gets the photo thumbnail column index if
+     * platform version &gt;= Honeycomb
+     */
+    if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB) {
+        mThumbnailColumn =
+                mCursor.getColumnIndex(Contacts.PHOTO_THUMBNAIL_URI);
+    // Otherwise, sets the thumbnail column to the _ID column
+    } else {
+        mThumbnailColumn = mIdColumn;
+    }
+    /*
+     * Assuming the current Cursor position is the contact you want,
+     * gets the thumbnail ID
+     */
+    mThumbnailUri = Cursor.getString(mThumbnailColumn);
+    ...
+</pre>
+<p>
+    Define a method that takes photo-related data for the contact and dimensions for the
+    destination view,  and returns the properly-sized thumbnail in a
+    {@link android.graphics.Bitmap}. Start by constructing a URI that points to the
+    thumbnail:
+<p>
+<pre>
+    /**
+     * Load a contact photo thumbnail and return it as a Bitmap,
+     * resizing the image to the provided image dimensions as needed.
+     * @param photoData photo ID Prior to Honeycomb, the contact's _ID value.
+     * For Honeycomb and later, the value of PHOTO_THUMBNAIL_URI.
+     * @return A thumbnail Bitmap, sized to the provided width and height.
+     * Returns null if the thumbnail is not found.
+     */
+    private Bitmap loadContactPhotoThumbnail(String photoData) {
+        // Creates an asset file descriptor for the thumbnail file.
+        AssetFileDescriptor afd = null;
+        // try-catch block for file not found
+        try {
+            // Creates a holder for the URI.
+            Uri thumbUri;
+            // If Android 3.0 or later
+            if (Build.VERSION.SDK_INT
+                    &gt;=
+                Build.VERSION_CODES.HONEYCOMB) {
+                // Sets the URI from the incoming PHOTO_THUMBNAIL_URI
+                thumbUri = Uri.parse(photoData);
+            } else {
+            // Prior to Android 3.0, constructs a photo Uri using _ID
+                /*
+                 * Creates a contact URI from the Contacts content URI
+                 * incoming photoData (_ID)
+                 */
+                final Uri contactUri = Uri.withAppendedPath(
+                        Contacts.CONTENT_URI, photoData);
+                /*
+                 * Creates a photo URI by appending the content URI of
+                 * Contacts.Photo.
+                 */
+                thumbUri =
+                        Uri.withAppendedPath(
+                                contactUri, Photo.CONTENT_DIRECTORY);
+            }
+    
+        /*
+         * Retrieves an AssetFileDescriptor object for the thumbnail
+         * URI
+         * using ContentResolver.openAssetFileDescriptor
+         */
+        afd = getActivity().getContentResolver().
+                openAssetFileDescriptor(thumbUri, "r");
+        /*
+         * Gets a file descriptor from the asset file descriptor.
+         * This object can be used across processes.
+         */
+        FileDescriptor fileDescriptor = afd.getFileDescriptor();
+        // Decode the photo file and return the result as a Bitmap
+        // If the file descriptor is valid
+        if (fileDescriptor != null) {
+            // Decodes the bitmap
+            return BitmapFactory.decodeFileDescriptor(
+                    fileDescriptor, null, null);
+            }
+        // If the file isn't found
+        } catch (FileNotFoundException e) {
+            /*
+             * Handle file not found errors
+             */
+        }
+        // In all cases, close the asset file descriptor
+        } finally {
+            if (afd != null) {
+                try {
+                    afd.close();
+                } catch (IOException e) {}
+            }
+        }
+        return null;
+    }
+</pre>
+<p>
+    Call the <code>loadContactPhotoThumbnail()</code> method in your code to get the
+    thumbnail {@link android.graphics.Bitmap}, and use the result to set the photo thumbnail in
+    your {@link android.widget.QuickContactBadge}:
+</p>
+<pre>
+    ...
+    /*
+     * Decodes the thumbnail file to a Bitmap.
+     */
+    Bitmap mThumbnail =
+            loadContactPhotoThumbnail(mThumbnailUri);
+    /*
+     * Sets the image in the QuickContactBadge
+     * QuickContactBadge inherits from ImageView, so
+     */
+    mBadge.setImageBitmap(mThumbnail);
+</pre>
+<h2 id="ListView">Add a QuickContactBadge to a ListView</h2>
+<p>
+    A {@link android.widget.QuickContactBadge} is a useful addition to a
+    {@link android.widget.ListView} that displays a list of contacts. Use the
+    {@link android.widget.QuickContactBadge} to display a thumbnail photo for each contact; when
+    users click the thumbnail, the {@link android.widget.QuickContactBadge} dialog appears.
+</p>
+<h3>Add the QuickContactBadge element</h3>
+<p>
+    To start, add a {@link android.widget.QuickContactBadge} view element to your item layout
+    For example, if you want to display a {@link android.widget.QuickContactBadge} and a name for
+    each contact you retrieve, put the following XML into a layout file:
+</p>
+<pre>
+&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"&gt;
+    &lt;QuickContactBadge
+        android:id="&#64;+id/quickcontact"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"/&gt;
+    &lt;TextView android:id="&#64;+id/displayname"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:layout_toRightOf="&#64;+id/quickcontact"
+              android:gravity="center_vertical"
+              android:layout_alignParentRight="true"
+              android:layout_alignParentTop="true"/&gt;
+&lt;/RelativeLayout&gt;
+</pre>
+<p>
+    In the following sections, this file is referred to as <code>contact_item_layout.xml</code>.
+</p>
+<h3>Set up a custom CursorAdapter</h3>
+<p>
+    To bind a {@link android.support.v4.widget.CursorAdapter} to a {@link android.widget.ListView}
+    containing a {@link android.widget.QuickContactBadge}, define a custom adapter that
+    extends {@link android.support.v4.widget.CursorAdapter}. This approach allows you to process the
+    data in the {@link android.database.Cursor} before you bind it to the
+    {@link android.widget.QuickContactBadge}. This approach also allows you to bind multiple
+    {@link android.database.Cursor} columns to the {@link android.widget.QuickContactBadge}. Neither
+    of these operations is possible in a regular {@link android.support.v4.widget.CursorAdapter}.
+</p>
+<p>
+    The subclass of {@link android.support.v4.widget.CursorAdapter} that you define must
+    override the following methods:
+</p>
+<dl>
+    <dt>{@link android.support.v4.widget.CursorAdapter#newView CursorAdapter.newView()}</dt>
+    <dd>
+        Inflates a new {@link android.view.View} object to hold the item layout. In the override
+        of this method, store handles to the child {@link android.view.View} objects of the layout,
+        including the child {@link android.widget.QuickContactBadge}. By taking this approach, you
+        avoid having to get handles to the child {@link android.view.View} objects each time you
+        inflate a new layout.
+        <p>
+            You must override this method so you can get handles to the individual child
+            {@link android.view.View} objects. This technique allows you to control their binding in
+            {@link android.support.v4.widget.CursorAdapter#bindView CursorAdapter.bindView()}.
+        </p>
+    </dd>
+    <dt>{@link android.support.v4.widget.CursorAdapter#bindView CursorAdapter.bindView()}</dt>
+    <dd>
+        Moves data from the current {@link android.database.Cursor} row to the child
+        {@link android.view.View} objects of the item layout. You must override this method so
+        you can bind both the contact's URI and thumbnail to the
+        {@link android.widget.QuickContactBadge}. The default implementation only allows a 1-to-1
+        mapping between a column and a {@link android.view.View}
+    </dd>
+</dl>
+<p>
+    The following code snippet contains an example of a custom subclass of
+    {@link android.support.v4.widget.CursorAdapter}:
+</p>
+<h3>Define the custom list adapter</h3>
+<p>
+    Define the subclass of {@link android.support.v4.widget.CursorAdapter} including its
+    constructor, and override
+    {@link android.support.v4.widget.CursorAdapter#newView newView()} and
+    {@link android.support.v4.widget.CursorAdapter#bindView bindView()}:
+</p>
+<pre>
+    /**
+     *
+     *
+     */
+    private class ContactsAdapter extends CursorAdapter {
+        private LayoutInflater mInflater;
+        ...
+        public ContactsAdapter(Context context) {
+            super(context, null, 0);
+
+            /*
+             * Gets an inflater that can instantiate
+             * the ListView layout from the file.
+             */
+            mInflater = LayoutInflater.from(context);
+            ...
+        }
+        ...
+        /**
+         * Defines a class that hold resource IDs of each item layout
+         * row to prevent having to look them up each time data is
+         * bound to a row.
+         */
+        private class ViewHolder {
+            TextView displayname;
+            QuickContactBadge quickcontact;
+        }
+        ..
+        &#64;Override
+        public View newView(
+                Context context,
+                Cursor cursor,
+                ViewGroup viewGroup) {
+            /* Inflates the item layout. Stores resource IDs in a
+             * in a ViewHolder class to prevent having to look
+             * them up each time bindView() is called.
+             */
+            final View itemView =
+                    mInflater.inflate(
+                            R.layout.contact_list_layout,
+                            viewGroup,
+                            false
+                    );
+            final ViewHolder holder = new ViewHolder();
+            holder.displayname =
+                    (TextView) view.findViewById(R.id.displayname);
+            holder.quickcontact =
+                    (QuickContactBadge)
+                            view.findViewById(R.id.quickcontact);
+            view.setTag(holder);
+            return view;
+        }
+        ...
+        &#64;Override
+        public void bindView(
+                View view,
+                Context context,
+                Cursor cursor) {
+            final ViewHolder holder = (ViewHolder) view.getTag();
+            final String photoData =
+                    cursor.getString(mPhotoDataIndex);
+            final String displayName =
+                    cursor.getString(mDisplayNameIndex);
+            ...
+            // Sets the display name in the layout
+            holder.displayname = cursor.getString(mDisplayNameIndex);
+            ...
+            /*
+             * Generates a contact URI for the QuickContactBadge.
+             */
+            final Uri contactUri = Contacts.getLookupUri(
+                    cursor.getLong(mIdIndex),
+                    cursor.getString(mLookupKeyIndex));
+            holder.quickcontact.assignContactUri(contactUri);
+            String photoData = cursor.getString(mPhotoDataIndex);
+            /*
+             * Decodes the thumbnail file to a Bitmap.
+             * The method loadContactPhotoThumbnail() is defined
+             * in the section "Set the Contact URI and Thumbnail"
+             */
+            Bitmap thumbnailBitmap =
+                    loadContactPhotoThumbnail(photoData);
+            /*
+             * Sets the image in the QuickContactBadge
+             * QuickContactBadge inherits from ImageView
+             */
+            holder.quickcontact.setImageBitmap(thumbnailBitmap);
+    }
+</pre>
+
+<h3>Set up variables</h3>
+<p>
+    In your code, set up variables, including a {@link android.database.Cursor} projection that
+    includes the necessary columns.
+</p>
+<p class="note">
+    <strong>Note:</strong> The following code snippets use the method
+    <code>loadContactPhotoThumbnail()</code>, which is defined in the section
+    <a href="#SetURIThumbnail">Set the Contact URI and Thumbnail</a>
+</p>
+<p>
+    For example:
+</p>
+<pre>
+public class ContactsFragment extends Fragment implements
+        LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
+...
+    // Defines a ListView
+    private ListView mListView;
+    // Defines a ContactsAdapter
+    private ContactsAdapter mAdapter;
+    ...
+    // Defines a Cursor to contain the retrieved data
+    private Cursor mCursor;
+    /*
+     * Defines a projection based on platform version. This ensures
+     * that you retrieve the correct columns.
+     */
+    private static final String[] PROJECTION =
+            {
+                Contacts._ID,
+                Contacts.LOOKUP_KEY,
+                (Build.VERSION.SDK_INT &gt;=
+                 Build.VERSION_CODES.HONEYCOMB) ?
+                        Contacts.DISPLAY_NAME_PRIMARY :
+                        Contacts.DISPLAY_NAME
+                (Build.VERSION.SDK_INT &gt;=
+                 Build.VERSION_CODES.HONEYCOMB) ?
+                        Contacts.PHOTO_THUMBNAIL_ID :
+                        /*
+                         * Although it's not necessary to include the
+                         * column twice, this keeps the number of
+                         * columns the same regardless of version
+                         */
+                        Contacts_ID
+                ...
+            };
+    /*
+     * As a shortcut, defines constants for the
+     * column indexes in the Cursor. The index is
+     * 0-based and always matches the column order
+     * in the projection.
+     */
+    // Column index of the _ID column
+    private int mIdIndex = 0;
+    // Column index of the LOOKUP_KEY column
+    private int mLookupKeyIndex = 1;
+    // Column index of the display name column
+    private int mDisplayNameIndex = 3;
+    /*
+     * Column index of the photo data column.
+     * It's PHOTO_THUMBNAIL_URI for Honeycomb and later,
+     * and _ID for previous versions.
+     */
+    private int mPhotoDataIndex =
+            Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
+            3 :
+            0;
+    ...
+</pre>
+<h3>Set up the ListView</h3>
+<p>
+    In {@link android.support.v4.app.Fragment#onCreate Fragment.onCreate()}, instantiate the custom
+    cursor adapter and get a handle to the {@link android.widget.ListView}:
+</p>
+<pre>
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        ...
+        /*
+         * Instantiates the subclass of
+         * CursorAdapter
+         */
+        ContactsAdapter mContactsAdapter =
+                new ContactsAdapter(getActivity());
+        /*
+         * Gets a handle to the ListView in the file
+         * contact_list_layout.xml
+         */
+        mListView = (ListView) findViewById(R.layout.contact_list_layout);
+        ...
+    }
+    ...
+</pre>
+<p>
+    In {@link android.support.v4.app.Fragment#onActivityCreated onActivityCreated()}, bind the
+    <code>ContactsAdapter</code> to the {@link android.widget.ListView}:
+</p>
+<pre>
+    &#64;Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        ...
+        // Sets up the adapter for the ListView
+        mListView.setAdapter(mAdapter);
+        ...
+    }
+    ...
+</pre>
+<p>
+    When you get back a {@link android.database.Cursor} containing the contacts data, usually in
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()},
+    call {@link android.support.v4.widget.CursorAdapter#swapCursor swapCursor()} to move the
+    {@link android.database.Cursor} data to the {@link android.widget.ListView}. This displays the
+    {@link android.widget.QuickContactBadge} for each entry in the list of contacts:
+</p>
+<pre>
+    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
+        // When the loader has completed, swap the cursor into the adapter.
+        mContactsAdapter.swapCursor(cursor);
+    }
+</pre>
+<p>
+    When you bind a {@link android.database.Cursor} to a
+    {@link android.widget.ListView} with a {@link android.support.v4.widget.CursorAdapter}
+    (or subclass), and you use a {@link android.support.v4.content.CursorLoader} to load the
+    {@link android.database.Cursor}, always clear references to the {@link android.database.Cursor}
+    in your implementation of
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}.
+    For example:
+</p>
+<pre>
+    &#64;Override
+    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
+        // Removes remaining reference to the previous Cursor
+        mContactsAdapter.swapCursor(null);
+    }
+</pre>
diff --git a/docs/html/training/contacts-provider/index.jd b/docs/html/training/contacts-provider/index.jd
new file mode 100644
index 0000000..f380d95
--- /dev/null
+++ b/docs/html/training/contacts-provider/index.jd
@@ -0,0 +1,97 @@
+page.title=Accessing Contacts Data
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 2.0 (API Level 5) or higher</li>
+  <li>Experience in using {@link android.content.Intent} objects</li>
+  <li>Experience in using content providers</li>
+</ul>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+        Contacts Provider</a>
+    </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+    <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+    Download the sample
+    </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>
+    The <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a> is
+    the central repository of the user's contacts information, including data from contacts apps and
+    social networking apps. In your apps, you can access Contacts Provider information directly by
+    calling {@link android.content.ContentResolver} methods or by sending intents to a contacts app.
+</p>
+<p>
+    This class focuses on retrieving lists of contacts, displaying the details for a particular
+    contact, and modifying contacts using intents. The basic techniques described
+    here can be extended to perform more complex tasks. In addition, this class helps you
+    understand the overall structure and operation of the
+    <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a>.
+</p>
+<h2>Lessons</h2>
+ 
+<dl>
+    <dt>
+        <b><a href="retrieve-names.html">Retrieving a List of Contacts</a></b>
+    </dt>
+    <dd>
+        Learn how to retrieve a list of contacts for which the data matches all or part of a search
+        string, using the following techniques:
+        <ul>
+            <li>Match by contact name</li>
+            <li>Match any type of contact data</li>
+            <li>Match a specific type of contact data, such as a phone number</li>
+        </ul>
+    </dd>
+    <dt>
+        <b><a href="retrieve-details.html">Retrieving Details for a Contact</a></b>
+    </dt>
+    <dd>
+        Learn how to retrieve the details for a single contact. A contact's details are data
+        such as phone numbers and email addresses. You can retrieve all details, or you can
+        retrieve details of a specific type, such as all email addresses.
+    </dd>
+    <dt>
+        <b><a href="modify-data.html">Modifying Contacts Using Intents</a></b>
+    </dt>
+    <dd>
+        Learn how to modify a contact by sending an intent to the People app.
+    </dd>
+    <dt>
+        <b>
+            <a href="display-contact-badge.html">Displaying the Quick Contact Badge</a>
+        </b>
+    </dt>
+    <dd>
+        Learn how to display the {@link android.widget.QuickContactBadge} widget. When the user
+        clicks the contact badge widget, a dialog opens that displays the contact's details and
+        action buttons for apps that can handle the details. For example, if the contact has an
+        email address, the dialog displays an action button for the default email app.
+    </dd>
+</dl>
diff --git a/docs/html/training/contacts-provider/modify-data.jd b/docs/html/training/contacts-provider/modify-data.jd
new file mode 100644
index 0000000..64853ef
--- /dev/null
+++ b/docs/html/training/contacts-provider/modify-data.jd
@@ -0,0 +1,305 @@
+page.title=Modifying Contacts Using Intents
+trainingnavtop=true
+@jd:body
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#InsertContact">Insert a New Contact Using an Intent</a></li>
+  <li><a href="#EditContact">Edit an Existing Contact Using an Intent</a></li>
+  <li><a href="#InsertEdit">Let Users Choose to Insert or Edit Using an Intent</a>
+</ol>
+<h2>You should also read</h2>
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics
+        </a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+        Contacts Provider
+        </a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
+    </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+    <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+    Download the sample
+    </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    This lesson shows you how to use an {@link android.content.Intent} to insert a new contact or
+    modify a contact's data. Instead of accessing the Contacts Provider directly, an
+    {@link android.content.Intent} starts the contacts app, which runs the appropriate
+    {@link android.app.Activity}. For the modification actions described in this lesson,
+    if you send extended data in the {@link android.content.Intent} it's entered into the UI of the
+    {@link android.app.Activity} that is started.
+</p>
+<p>
+    Using an {@link android.content.Intent} to insert or update a single contact is the preferred
+    way of modifying the Contacts Provider, for the following reasons:
+</p>
+<ul>
+    <li>It saves you the time and and effort of developing your own UI and code.</li>
+    <li>
+        It avoids introducing errors caused by modifications that don't follow the
+        Contacts Provider's rules.
+    </li>
+    <li>
+        It reduces the number of permissions you need to request. Your app doesn't need permission
+        to write to the Contacts Provider, because it delegates modifications to the contacts app,
+        which already has that permission.
+    </li>
+</ul>
+<h2 id="InsertContact">Insert a New Contact Using an Intent</h2>
+<p>
+    You often want to allow the user to insert a new contact when your app receives new data. For
+    example, a restaurant review app can allow users to add the restaurant as a contact as they're
+    reviewing it. To do this using an intent, create the intent using as much data as you have
+    available, and then send the intent to the contacts app.
+</p>
+<p>
+    Inserting a contact using the contacts app inserts a new <em>raw</em> contact into the Contacts
+    Provider's {@link android.provider.ContactsContract.RawContacts} table.  If necessary,
+    the contacts app prompts users for the account type and account to use when creating the raw
+    contact. The contacts app also notifies users if the raw contact already exists. Users then have
+    option of canceling the insertion, in which case no contact is created. To learn
+    more about raw contacts, see the
+    <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a>
+    API guide.
+</p>
+
+<h3>Create an Intent</h3>
+<p>
+    To start, create a new {@link android.content.Intent} object with the action
+    {@link android.provider.ContactsContract.Intents.Insert#ACTION Intents.Insert.ACTION}.
+    Set the MIME type to {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE
+    RawContacts.CONTENT_TYPE}. For example:
+</p>
+<pre>
+...
+// Creates a new Intent to insert a contact
+Intent intent = new Intent(Intents.Insert.ACTION);
+// Sets the MIME type to match the Contacts Provider
+intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
+</pre>
+<p>
+    If you already have details for the contact, such as a phone number or email address, you can
+    insert them into the intent as extended data. For a key value, use the appropriate constant from
+    {@link android.provider.ContactsContract.Intents.Insert Intents.Insert}. The contacts app
+    displays the data in its insert screen, allowing users to make further edits and additions.
+</p>
+<pre>
+/* Assumes EditText fields in your UI contain an email address
+ * and a phone number.
+ *
+ */
+private EditText mEmailAddress = (EditText) findViewById(R.id.email);
+private EditText mPhoneNumber = (EditText) findViewById(R.id.phone);
+...
+/*
+ * Inserts new data into the Intent. This data is passed to the
+ * contacts app's Insert screen
+ */
+// Inserts an email address
+intent.putExtra(Intents.Insert.EMAIL, mEmailAddress.getText())
+/*
+ * In this example, sets the email type to be a work email.
+ * You can set other email types as necessary.
+ */
+      .putExtra(Intents.Insert.EMAIL_TYPE, CommonDataKinds.Email.TYPE_WORK)
+// Inserts a phone number
+      .putExtra(Intents.Insert.PHONE, mPhoneNumber.getText())
+/*
+ * In this example, sets the phone type to be a work phone.
+ * You can set other phone types as necessary.
+ */
+      .putExtra(Intents.Insert.PHONE_TYPE, Phone.TYPE_WORK);
+
+</pre>
+<p>
+    Once you've created the {@link android.content.Intent}, send it by calling
+    {@link android.support.v4.app.Fragment#startActivity startActivity()}.
+</p>
+<pre>
+    /* Sends the Intent
+     */
+    startActivity(intent);
+</pre>
+<p>
+    This call opens a screen in the contacts app that allows users to enter a new contact. The
+    account type and account name for the contact is listed at the top of the screen. Once users
+    enter the data and click <i>Done</i>, the contacts app's contact list appears. Users return to
+    your app by clicking <i>Back</i>.
+</p>
+<h2 id="EditContact">Edit an Existing Contact Using an Intent</h2>
+<p>
+    Editing an existing contact using an {@link android.content.Intent} is useful if the user
+    has already chosen a contact of interest. For example, an app that finds contacts that have
+    postal addresses but lack a postal code could give users the option of looking up the code and
+    then adding it to the contact.
+</p>
+<p>
+    To edit an existing contact using an intent, use a procedure similar to
+    inserting a contact. Create an intent as described in the section
+    <a href="#InsertContact">Insert a New Contact Using an Intent</a>, but add the contact's
+    {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI
+    Contacts.CONTENT_LOOKUP_URI} and the MIME type
+    {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
+    Contacts.CONTENT_ITEM_TYPE} to the intent. If you want to edit the contact with details you
+    already have, you can put them in the intent's extended data. Notice that some
+    name columns can't be edited using an intent; these columns are listed in the summary
+    section of the API reference for the class {@link android.provider.ContactsContract.Contacts}
+    under the heading "Update".
+</p>
+<p>
+    Finally, send the intent. In response, the contacts app displays an edit screen. When the user
+    finishes editing and saves the edits, the contacts app displays a contact list. When the user
+    clicks <i>Back</i>, your app is displayed.
+</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+    <h2>Contacts Lookup Key</h2>
+    <p>
+        A contact's {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} value is
+        the identifier that you should use to retrieve a contact. It remains constant,
+        even if the provider changes the contact's row ID to handle internal operations.
+    </p>
+</div>
+</div>
+<h3>Create the Intent</h3>
+<p>
+    To edit a contact, call {@link android.content.Intent#Intent Intent(action)} to
+    create an intent with the action {@link android.content.Intent#ACTION_EDIT}. Call
+    {@link android.content.Intent#setDataAndType setDataAndType()} to set the data value for the
+    intent to the contact's {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI
+    Contacts.CONTENT_LOOKUP_URI} and the MIME type to
+    {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
+    Contacts.CONTENT_ITEM_TYPE} MIME type; because a call to
+    {@link android.content.Intent#setType setType()} overwrites the current data value for the
+    {@link android.content.Intent}, you must set the data and the MIME type at the same time.
+</p>
+<p>
+    To get a contact's {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI
+    Contacts.CONTENT_LOOKUP_URI}, call
+    {@link android.provider.ContactsContract.Contacts#getLookupUri
+    Contacts.getLookupUri(id, lookupkey)} with the contact's
+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
+    arguments.
+</p>
+<p>
+    The following snippet shows you how to create an intent:
+</p>
+<pre>
+    // The Cursor that contains the Contact row
+    public Cursor mCursor;
+    // The index of the lookup key column in the cursor
+    public int mLookupKeyIndex;
+    // The index of the contact's _ID value
+    public int mIdIndex;
+    // The lookup key from the Cursor
+    public String mCurrentLookupKey;
+    // The _ID value from the Cursor
+    public long mCurrentId;
+    // A content URI pointing to the contact
+    Uri mSelectedContactUri;
+    ...
+    /*
+     * Once the user has selected a contact to edit,
+     * this gets the contact's lookup key and _ID values from the
+     * cursor and creates the necessary URI.
+     */
+    // Gets the lookup key column index
+    mLookupKeyIndex = mCursor.getColumnIndex(Contacts.LOOKUP_KEY);
+    // Gets the lookup key value
+    mCurrentLookupKey = mCursor.getString(mLookupKeyIndex);
+    // Gets the _ID column index
+    mIdIndex = mCursor.getColumnIndex(Contacts._ID);
+    mCurrentId = mCursor.getLong(mIdIndex);
+    mSelectedContactUri =
+            Contacts.getLookupUri(mCurrentId, mCurrentLookupKey);
+    ...
+    // Creates a new Intent to edit a contact
+    Intent editIntent = new Intent(Intent.ACTION_EDIT);
+    /*
+     * Sets the contact URI to edit, and the data type that the
+     * Intent must match
+     */
+    editIntent.setDataAndType(mSelectedContactUri,Contacts.CONTENT_ITEM_TYPE);
+</pre>
+<h3>Add the navigation flag</h3>
+<p>
+    In Android 4.0 (API version 14) and later, a problem in the contacts app causes incorrect
+    navigation. When your app sends an edit intent to the contacts app, and users edit and save a
+    contact, when they click <i>Back</i> they see the contacts list screen. To navigate back to
+    your app, they have to click <i>Recents</i> and choose your app.
+</p>
+<p>
+    To work around this problem in Android 4.0.3 (API version 15) and later, add the extended
+    data key {@code finishActivityOnSaveCompleted} to the intent, with a value of {@code true}.
+    Android versions prior to Android 4.0 accept this key, but it has no effect. To set the
+    extended data, do the following:
+</p>
+<pre>
+    // Sets the special extended data for navigation
+    editIntent.putExtra("finishActivityOnSaveCompleted", true);
+</pre>
+<h3>Add other extended data</h3>
+<p>
+    To add additional extended data to the {@link android.content.Intent}, call
+    {@link android.content.Intent#putExtra putExtra()} as desired.
+    You can add extended data for common contact fields by using the key values specified in
+    {@link android.provider.ContactsContract.Intents.Insert Intents.Insert}. Remember that some
+    columns in the {@link android.provider.ContactsContract.Contacts} table can't be modified.
+    These columns are listed in the summary section of the API reference for the class
+    {@link android.provider.ContactsContract.Contacts} under the heading "Update".
+</p>
+
+<h3>Send the Intent</h3>
+<p>
+    Finally, send the intent you've constructed. For example:
+</p>
+<pre>
+    // Sends the Intent
+    startActivity(editIntent);
+</pre>
+<h2 id="InsertEdit">Let Users Choose to Insert or Edit Using an Intent</h2>
+<p>
+    You can allow users to choose whether to insert a contact or edit an existing one by sending
+    an {@link android.content.Intent} with the action
+    {@link android.content.Intent#ACTION_INSERT_OR_EDIT}. For example, an email client app could
+    allow users to add an incoming email address to a new contact, or add it as an additional
+    address for an existing contact. Set the MIME type for this intent to
+    {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE Contacts.CONTENT_ITEM_TYPE},
+    but don't set the data URI.
+</p>
+<p>
+    When you send this intent, the contacts app displays a list of contacts.
+    Users can either insert a new contact or pick an existing contact and edit it.
+    Any extended data fields you add to the intent populates the screen that appears. You can use
+    any of the key values specified in {@link android.provider.ContactsContract.Intents.Insert
+    Intents.Insert}. The following code snippet shows how to construct and send the intent:
+</p>
+<pre>
+    // Creates a new Intent to insert or edit a contact
+    Intent intentInsertEdit = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+    // Sets the MIME type
+    intentInsertEdit.setType(Contacts.CONTENT_ITEM_TYPE);
+    // Add code here to insert extended data, if desired
+    ...
+    // Sends the Intent with an request ID
+    startActivity(intentInsertEdit);
+</pre>
diff --git a/docs/html/training/contacts-provider/retrieve-details.jd b/docs/html/training/contacts-provider/retrieve-details.jd
new file mode 100644
index 0000000..0de3b67
--- /dev/null
+++ b/docs/html/training/contacts-provider/retrieve-details.jd
@@ -0,0 +1,378 @@
+page.title=Retrieving Details for a Contact
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#RetrieveAll">Retrieve All Details for a Contact</a></li>
+  <li><a href="#RetrieveSpecific">Retrieve Specific Details for a Contact</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+        Contacts Provider</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/components/loaders.html">Loaders</a>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+    <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+    Download the sample
+    </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    This lesson shows how to retrieve detail data for a contact, such as email addresses, phone
+    numbers, and so forth. It's the details that users are looking for when they retrieve a contact.
+    You can give them all the details for a contact, or only display details of a particular type,
+    such as email addresses.
+</p>
+<p>
+    The steps in this lesson assume that you already have a
+    {@link android.provider.ContactsContract.Contacts} row for a contact the user has picked.
+    The <a href="retrieve-names.html">Retrieving Contact Names</a> lesson shows how to
+    retrieve a list of contacts.
+</p>
+<h2 id="RetrieveAll">Retrieve All Details for a Contact</h2>
+<p>
+    To retrieve all the details for a contact, search the
+    {@link android.provider.ContactsContract.Data} table for any rows that contain the contact's
+    {@link android.provider.ContactsContract.Data#LOOKUP_KEY}. This column is available in
+    the {@link android.provider.ContactsContract.Data} table, because the Contacts
+    Provider makes an implicit join between the {@link android.provider.ContactsContract.Contacts}
+    table and the {@link android.provider.ContactsContract.Data} table. The
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} column is described
+    in more detail in the <a href="retrieve-names.html">Retrieving Contact Names</a> lesson.
+</p>
+<p class="note">
+    <strong>Note:</strong> Retrieving all the details for a contact reduces the performance of a
+    device, because it needs to retrieve all of the columns in the
+    {@link android.provider.ContactsContract.Data} table. Consider the performance impact before
+    you use this technique.
+</p>
+<h3>Request permissions</h3>
+<p>
+    To read from the Contacts Provider, your app must have
+    {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission.
+    To request this permission, add the following child element of
+    <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">
+    &lt;manifest&gt;</a></code> to your manifest file:
+</p>
+<pre>
+    &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
+</pre>
+<h3>Set up a projection</h3>
+<p>
+    Depending on the data type a row contains, it may use only a few columns or many. In addition,
+    the data is in different columns depending on the data type.
+    To ensure you get all the possible columns for all possible data types, you need to add all the
+    column names to your projection. Always retrieve
+    {@link android.provider.ContactsContract.Data#_ID Data._ID} if you're binding the result
+    {@link android.database.Cursor} to a {@link android.widget.ListView}; otherwise, the binding
+    won't work. Also retrieve {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}
+    so you can identify the data type of each row you retrieve. For example:
+</p>
+<pre>
+    private static final String PROJECTION =
+            {
+                Data._ID,
+                Data.MIMETYPE,
+                Data.DATA1,
+                Data.DATA2,
+                Data.DATA3,
+                Data.DATA4,
+                Data.DATA5,
+                Data.DATA6,
+                Data.DATA7,
+                Data.DATA8,
+                Data.DATA9,
+                Data.DATA10,
+                Data.DATA11,
+                Data.DATA12,
+                Data.DATA13,
+                Data.DATA14,
+                Data.DATA15
+            };
+</pre>
+<p>
+    This projection retrieves all the columns for a row in the
+    {@link android.provider.ContactsContract.Data} table, using the column names defined in
+    the {@link android.provider.ContactsContract.Data} class.
+</p>
+<p>
+    Optionally, you can also use any other column constants defined in or inherited by the
+    {@link android.provider.ContactsContract.Data} class. Notice, however, that the columns
+    {@link android.provider.ContactsContract.DataColumns#SYNC1} through
+    {@link android.provider.ContactsContract.DataColumns#SYNC4} are meant to be used by sync
+    adapters, so their data is not useful.
+</p>
+<h3>Define the selection criteria</h3>
+<p>
+    Define a constant for your selection clause, an array to hold selection arguments, and a
+    variable to hold the selection value. Use
+    the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
+    find the contact. For example:
+</p>
+<pre>
+    // Defines the selection clause
+    private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
+    // Defines the array to hold the search criteria
+    private String[] mSelectionArgs = { "" };
+    /*
+     * Defines a variable to contain the selection value. Once you
+     * have the Cursor from the Contacts table, and you've selected
+     * the desired row, move the row's LOOKUP_KEY value into this
+     * variable.
+     */
+    private String mLookupKey;
+</pre>
+<p>
+    Using "?" as a placeholder in your selection text expression ensures that the resulting search
+    is generated by binding rather than SQL compilation. This approach eliminates the
+    possibility of malicious SQL injection.
+</p>
+<h3>Define the sort order</h3>
+<p>
+    Define the sort order you want in the resulting {@link android.database.Cursor}. To
+    keep all rows for a particular data type together, sort by
+    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}. This query argument
+    groups all email rows together, all phone rows together, and so forth. For example:
+</p>
+<pre>
+    /*
+     * Defines a string that specifies a sort order of MIME type
+     */
+    private static final String SORT_ORDER = Data.MIMETYPE;
+</pre>
+<p class="note">
+    <strong>Note:</strong> Some data types don't use a subtype, so you can't sort on subtype.
+    Instead, you have to iterate through the returned {@link android.database.Cursor},
+    determine the data type of the current row, and store data for rows that use a subtype. When
+    you finish reading the cursor, you can then sort each data type by subtype and display the
+    results.
+</p>
+<h3>Initialize the Loader</h3>
+<p>
+   Always do retrievals from the Contacts Provider (and all other content providers) in a
+   background thread. Use the Loader framework defined by the
+   {@link android.support.v4.app.LoaderManager} class and the
+   {@link android.support.v4.app.LoaderManager.LoaderCallbacks} interface to do background
+   retrievals.
+</p>
+<p>
+    When you're ready to retrieve the rows, initialize the loader framework by
+    calling {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. Pass an
+    integer identifier to the method; this identifier is passed to
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks} methods. The identifier helps you
+    use multiple loaders in an app by allowing you to differentiate between them.
+</p>
+<p>
+    The following snippet shows how to initialize the loader framework:
+</p>
+<pre>
+public class DetailsFragment extends Fragment implements
+        LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
+    ...
+    // Defines a constant that identifies the loader
+    DETAILS_QUERY_ID = 0;
+    ...
+    /*
+     * Invoked when the parent Activity is instantiated
+     * and the Fragment's UI is ready. Put final initialization
+     * steps here.
+     */
+    &#64;Override
+    onActivityCreated(Bundle savedInstanceState) {
+        ...
+        // Initializes the loader framework
+        getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
+</pre>
+<h3>Implement onCreateLoader()</h3>
+<p>
+    Implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
+    onCreateLoader()} method, which is called by the loader framework immediately after you call
+    {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. Return a
+    {@link android.support.v4.content.CursorLoader} from this method. Since you're searching
+    the {@link android.provider.ContactsContract.Data} table, use the constant
+    {@link android.provider.ContactsContract.Data#CONTENT_URI Data.CONTENT_URI} as the content URI.
+    For example:
+</p>
+<pre>
+    &#64;Override
+    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
+        // Choose the proper action
+        switch (loaderId) {
+            case DETAILS_QUERY_ID:
+            // Assigns the selection parameter
+            mSelectionArgs[0] = mLookupKey;
+            // Starts the query
+            CursorLoader mLoader =
+                    new CursorLoader(
+                            getActivity(),
+                            Data.CONTENT_URI,
+                            PROJECTION,
+                            SELECTION,
+                            mSelectionArgs,
+                            SORT_ORDER
+                    );
+            ...
+    }
+</pre>
+<h3>Implement onLoadFinished() and onLoaderReset()</h3>
+<p>
+    Implement the
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+    method. The loader framework calls
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+    when the Contacts Provider returns the results of the query. For example:
+</p>
+<pre>
+    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
+        switch (loader.getId()) {
+            case DETAILS_QUERY_ID:
+                    /*
+                     * Process the resulting Cursor here.
+                     */
+                }
+                break;
+            ...
+        }
+    }
+</pre>
+<p>
+<p>
+    The method {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset
+    onLoaderReset()} is invoked when the loader framework detects that the data backing the result
+    {@link android.database.Cursor} has changed. At this point, remove any existing references
+    to the {@link android.database.Cursor} by setting them to null. If you don't, the loader
+    framework won't destroy the old {@link android.database.Cursor}, and you'll get a memory
+    leak. For example:
+<pre>
+    &#64;Override
+    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
+        switch (loader.getId()) {
+            case DETAILS_QUERY_ID:
+                /*
+                 * If you have current references to the Cursor,
+                 * remove them here.
+                 */
+                }
+                break;
+    }
+</pre>
+<h2 id="RetrieveSpecific">Retrieve Specific Details for a Contact</h2>
+<p>
+    Retrieving a specific data type for a contact, such as all the emails, follows the same pattern
+    as retrieving all details. These are the only changes you need to make to the code
+    listed in <a href="#RetrieveAll">Retrieve All Details for a Contact</a>:
+</p>
+<dl>
+    <dt>
+        Projection
+    </dt>
+    <dd>
+        Modify your projection to retrieve the columns that are specific to the
+        data type. Also modify the projection to use the column name constants defined in the
+        {@link android.provider.ContactsContract.CommonDataKinds} subclass corresponding to the
+        data type.
+    </dd>
+    <dt>
+        Selection
+    </dt>
+    <dd>
+        Modify the selection text to search for the
+        {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value that's specific to
+        your data type.
+    </dd>
+    <dt>
+        Sort order
+    </dt>
+    <dd>
+        Since you're only selecting a single detail type, don't group the returned
+        {@link android.database.Cursor} by {@link android.provider.ContactsContract.Data#MIMETYPE
+        Data.MIMETYPE}.
+    </dd>
+</dl>
+<p>
+    These modifications are described in the following sections.
+</p>
+<h3>Define a projection</h3>
+<p>
+    Define the columns you want to retrieve, using the column name constants in the subclass
+    of {@link android.provider.ContactsContract.CommonDataKinds} for the data type.
+    If you plan to bind your {@link android.database.Cursor} to a {@link android.widget.ListView},
+    be sure to retrieve the <code>_ID</code> column. For example, to retrieve email data, define the
+    following projection:
+</p>
+<pre>
+    private static final String[] PROJECTION =
+            {
+                Email._ID,
+                Email.ADDRESS,
+                Email.TYPE,
+                Email.LABEL
+            };
+</pre>
+<p>
+    Notice that this projection uses the column names defined in the class
+    {@link android.provider.ContactsContract.CommonDataKinds.Email}, instead of the column names
+    defined in the class {@link android.provider.ContactsContract.Data}. Using the email-specific
+    column names makes the code more readable.
+</p>
+<p>
+    In the projection, you can also use any of the other columns defined in the
+    {@link android.provider.ContactsContract.CommonDataKinds} subclass.
+</p>
+<h3>Define selection criteria</h3>
+<p>
+    Define a search text expression that retrieves rows for a specific contact's
+    {@link android.provider.ContactsContract.Data#LOOKUP_KEY} and the
+    {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE} of the details you
+    want. Enclose the {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value in
+    single quotes by concatenating a "<code>'</code>" (single-quote) character to the start and end
+    of the constant; otherwise, the provider interprets the constant as a variable name rather
+    than as a string value. You don't need to use a placeholder for this value, because you're
+    using a constant rather than a user-supplied value. For example:
+</p>
+<pre>
+    /*
+     * Defines the selection clause. Search for a lookup key
+     * and the Email MIME type
+     */
+    private static final String SELECTION =
+            Data.LOOKUP_KEY + " = ?" +
+            " AND " +
+            Data.MIMETYPE + " = " +
+            "'" + Email.CONTENT_ITEM_TYPE + "'";
+    // Defines the array to hold the search criteria
+    private String[] mSelectionArgs = { "" };
+</pre>
+<h3>Define a sort order</h3>
+<p>
+    Define a sort order for the returned {@link android.database.Cursor}. Since you're retrieving a
+    specific data type, omit the sort on {@link android.provider.ContactsContract.Data#MIMETYPE}.
+    Instead, if the type of detail data you're searching includes a subtype, sort on it.
+    For example, for email data you can sort on
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#TYPE Email.TYPE}:
+</p>
+<pre>
+    private static final String SORT_ORDER = Email.TYPE + " ASC ";
+</pre>
diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd
new file mode 100644
index 0000000..b034a6a
--- /dev/null
+++ b/docs/html/training/contacts-provider/retrieve-names.jd
@@ -0,0 +1,815 @@
+page.title=Retrieving a List of Contacts
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#Permissions">Request Permission to Read the Provider</a>
+  <li><a href="#NameMatch">Match a Contact by Name and List the Results</a></li>
+  <li><a href="#TypeMatch">Match a Contact By a Specific Type of Data</a></li>
+  <li><a href="#GeneralMatch">Match a Contact By Any Type of Data</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+        Contacts Provider</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/components/loaders.html">Loaders</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>
+    </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+    <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+    Download the sample
+    </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+    This lesson shows you how to retrieve a list of contacts whose data matches all or part of a
+    search string, using the following techniques:
+</p>
+<dl>
+    <dt>Match contact names</dt>
+    <dd>
+        Retrieve a list of contacts by matching the search string to all or part of the contact
+        name data. The Contacts Provider allows multiple instances of the same name, so this
+        technique can return a list of matches.
+    </dd>
+    <dt>Match a specific type of data, such as a phone number</dt>
+    <dd>
+        Retrieve a list of contacts by matching the search string to a particular type of detail
+        data such as an email address. For example, this technique allows you to list all of the
+        contacts whose email address matches the search string.
+    </dd>
+    <dt>Match any type of data</dt>
+    <dd>
+        Retrieve a list of contacts by matching the search string to any type of detail data,
+        including name, phone number, street address, email address, and so forth. For example,
+        this technique allows you to accept any type of data for a search string and then list the
+        contacts for which the data matches the string.
+    </dd>
+</dl>
+<p class="note">
+    <strong>Note:</strong> All the examples in this lesson use a
+    {@link android.support.v4.content.CursorLoader} to retrieve data from the Contacts
+    Provider. A {@link android.support.v4.content.CursorLoader} runs its query on a
+    thread that's separate from the UI thread. This ensures that the query doesn't slow down UI
+    response times and cause a poor user experience. For more information, see the Android
+    training class <a href="{@docRoot}training/load-data-background/index.html">
+    Loading Data in the Background</a>.
+</p>
+<h2 id="Permissions">Request Permission to Read the Provider</h2>
+<p>
+    To do any type of search of the Contacts Provider, your app must have
+    {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission.
+    To request this, add this
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+    element to your manifest file as a child element of
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>:
+</p>
+<pre>
+    &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
+</pre>
+<h2 id="NameMatch">Match a Contact by Name and List the Results</h2>
+<p>
+    This technique tries to match a search string to the name of a contact or contacts in the
+    Contact Provider's {@link android.provider.ContactsContract.Contacts} table. You usually want
+    to display the results in a {@link android.widget.ListView}, to allow the user to choose among
+    the matched contacts.
+</p>
+<h3 id="DefineListView">Define ListView and item layouts</h3>
+<p>
+    To display the search results in a {@link android.widget.ListView}, you need a main layout file
+    that defines the entire UI including the {@link android.widget.ListView}, and an item layout
+    file that defines one line of the {@link android.widget.ListView}. For example, you can define
+    the main layout file <code>res/layout/contacts_list_view.xml</code> that contains the
+    following XML:
+</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;ListView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:id="&#64;android:id/list"
+          android:layout_width="match_parent"
+          android:layout_height="match_parent"/&gt;
+</pre>
+<p>
+    This XML uses the built-in Android {@link android.widget.ListView} widget
+    {@link android.R.id#list android:id/list}.
+</p>
+<p>
+    Define the item layout file <code>contacts_list_item.xml</code> with the following XML:
+</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:id="&#64;android:id/text1"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:clickable="true"/&gt;
+</pre>
+<p>
+    This XML uses the built-in Android {@link android.widget.TextView} widget
+    {@link android.R.id#text1 android:text1}.
+</p>
+<p class="note">
+    <strong>Note:</strong> This lesson doesn't describe the UI for getting a search string from the
+    user, because you may want to get the string indirectly. For example, you can give the user
+    an option to search for contacts whose name matches a string in an incoming text message.
+</p>
+<p>
+    The two layout files you've written define a user interface that shows a
+    {@link android.widget.ListView}. The next step is to write code that uses this UI to display a
+    list of contacts.
+</p>
+<h3 id="Fragment">Define a Fragment that displays the list of contacts</h3>
+<p>
+    To display the list of contacts, start by defining a {@link android.support.v4.app.Fragment}
+    that's loaded by an {@link android.app.Activity}. Using a
+    {@link android.support.v4.app.Fragment} is a more flexible technique, because you can use
+    one {@link android.support.v4.app.Fragment} to display the list and a second
+    {@link android.support.v4.app.Fragment} to display the details for a contact that the user
+    chooses from the list. Using this approach, you can combine one of the techniques presented in
+    this lesson with one from the lesson <a href="retrieve-details.html">
+    Retrieving Details for a Contact</a>.
+</p>
+<p>
+    To learn how to use one or more {@link android.support.v4.app.Fragment} objects from an
+    an {@link android.app.Activity}, read the training class
+    <a href="{@docRoot}training/basics/fragments/index.html">
+    Building a Dynamic UI with Fragments</a>.
+</p>
+<p>
+    To help you write queries against the Contacts Provider, the Android framework provides a
+    contracts class called {@link android.provider.ContactsContract}, which defines useful
+    constants and methods for accessing the provider. When you use this class, you don't have to
+    define your own constants for content URIs, table names, or columns. To use this class,
+    include the following statement:
+</p>
+<pre>
+import android.provider.ContactsContract;
+</pre>
+<p>
+    Since the code uses a {@link android.support.v4.content.CursorLoader} to retrieve data
+    from the provider, you must specify that it implements the loader interface
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks}. Also, to help detect which contact
+    the user selects from the list of search results, implement the adapter interface
+    {@link android.widget.AdapterView.OnItemClickListener}. For example:
+</p>
+<pre>
+...
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
+import android.widget.AdapterView;
+...
+public class ContactsFragment extends Fragment implements
+        LoaderManager.LoaderCallbacks&lt;Cursor&gt;,
+        AdapterView.OnItemClickListener {
+</pre>
+<h3 id="DefineVariables">Define global variables</h3>
+<p>
+    Define global variables that are used in other parts of the code:
+</p>
+<pre>
+    ...
+    /*
+     * Defines an array that contains column names to move from
+     * the Cursor to the ListView.
+     */
+    &#64;SuppressLint("InlinedApi")
+    private final static String[] FROM_COLUMNS = {
+            Build.VERSION.SDK_INT
+                    &gt;= Build.VERSION_CODES.HONEYCOMB ?
+                    Contacts.DISPLAY_NAME_PRIMARY :
+                    Contacts.DISPLAY_NAME
+    };
+    /*
+     * Defines an array that contains resource ids for the layout views
+     * that get the Cursor column contents. The id is pre-defined in
+     * the Android framework, so it is prefaced with "android.R.id"
+     */
+    private final static int[] TO_IDS = {
+           android.R.id.text1
+    };
+    // Define global mutable variables
+    // Define a ListView object
+    ListView mContactsList;
+    // Define variables for the contact the user selects
+    // The contact's _ID value
+    long mContactId;
+    // The contact's LOOKUP_KEY
+    String mContactKey;
+    // A content URI for the selected contact
+    Uri mContactUri;
+    // An adapter that binds the result Cursor to the ListView
+    private SimpleCursorAdapter mCursorAdapter;
+    ...
+</pre>
+<p class="note">
+    <strong>Note:</strong> Since
+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
+    Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
+    app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
+    Eclipse with ADK. To turn off this warning, add the annotation
+    <code>@SuppressLint("InlinedApi")</code> before the definition of <code>FROM_COLUMNS</code>.
+</p>
+<h3 id="InitializeFragment">Initialize the Fragment</h3>
+<p>
+
+    Initialize the {@link android.support.v4.app.Fragment}. Add the empty, public constructor
+    required by the Android system, and inflate the {@link android.support.v4.app.Fragment} object's
+    UI in the callback method {@link android.support.v4.app.Fragment#onCreateView onCreateView()}.
+    For example:
+</p>
+<pre>
+    // Empty public constructor, required by the system
+    public ContactsFragment() {}
+
+    // A UI Fragment must inflate its View
+    &#64;Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        // Inflate the fragment layout
+        return inflater.inflate(R.layout.contacts_list_layout, container, false);
+    }
+</pre>
+<h3 id="DefineAdapter">Set up the CursorAdapter for the ListView</h3>
+<p>
+    Set up the {@link android.support.v4.widget.SimpleCursorAdapter} that binds the results of the
+    search to the {@link android.widget.ListView}. To get the {@link android.widget.ListView} object
+    that displays the contacts, you need to call {@link android.app.Activity#findViewById
+    Activity.findViewById()} using the parent activity of the
+    {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
+    parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
+    For example:
+</p>
+<pre>
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        ...
+        // Gets the ListView from the View list of the parent activity
+        mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view);
+        // Gets a CursorAdapter
+        mCursorAdapter = new SimpleCursorAdapter(
+                getActivity(),
+                R.layout.contact_list_item,
+                null,
+                FROM_COLUMNS, TO_IDS,
+                0);
+        // Sets the adapter for the ListView
+        mContactsList.setAdapter(mCursorAdapter);
+    }
+</pre>
+<h3 id="SetListener">Set the selected contact listener</h3>
+<p>
+    When you display the results of a search, you usually want to allow the user to select a
+    single contact for further processing. For example, when the user clicks a contact you can
+    display the contact's address on a map. To provide this feature, you first defined the current
+    {@link android.support.v4.app.Fragment} as the click listener by specifying that the class
+    implements {@link android.widget.AdapterView.OnItemClickListener}, as shown in the section
+    <a href="#Fragment">Define a Fragment that displays the list of contacts</a>.
+</p>
+<p>
+    To continue setting up the listener, bind it to the {@link android.widget.ListView} by
+    calling the method {@link android.widget.ListView#setOnItemClickListener
+    setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
+    onActivityCreated()}. For example:
+</p>
+<pre>
+    public void onActivityCreated(Bundle savedInstanceState) {
+        ...
+        // Set the item click listener to be the current fragment.
+        mContactsList.setOnItemClickListener(this);
+        ...
+    }
+</pre>
+<p>
+    Since you specified that the current {@link android.support.v4.app.Fragment} is the
+    {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} for the
+    {@link android.widget.ListView}, you now need to implement its required method
+    {@link android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()}, which
+    handles the click event. This is described in a succeeding section.
+</p>
+<h3 id="DefineProjection">Define a projection</h3>
+<p>
+    Define a constant that contains the columns you want to return from your query. Each item in
+    the {@link android.widget.ListView} displays the contact's display name,
+    which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
+    the name of this column is
+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
+    Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
+    {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
+</p>
+<p>
+    The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
+    {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
+    {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+    {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
+    construct a content URI for the contact the user selects.
+</p>
+<pre>
+...
+&#64;SuppressLint("InlinedApi")
+private static final String[] PROJECTION =
+        {
+            Contacts._ID,
+            Contacts.LOOKUP_KEY,
+            Build.VERSION.SDK_INT
+                    &gt;= Build.VERSION_CODES.HONEYCOMB ?
+                    Contacts.DISPLAY_NAME_PRIMARY :
+                    Contacts.DISPLAY_NAME
+
+        };
+</pre>
+<h3 id="DefineConstants">Define constants for the Cursor column indexes</h3>
+<p>
+    To get data from an individual column in a {@link android.database.Cursor}, you need
+    the column's index within the {@link android.database.Cursor}. You can define constants
+    for the indexes of the {@link android.database.Cursor} columns, because the indexes are
+    the same as the order of the column names in your projection. For example:
+</p>
+<pre>
+// The column index for the _ID column
+private static final int CONTACT_ID_INDEX = 0;
+// The column index for the LOOKUP_KEY column
+private static final int LOOKUP_KEY_INDEX = 1;
+</pre>
+<h3 id="SelectionCriteria">Specify the selection criteria</h3>
+<p>
+    To specify the data you want, create a combination of text expressions and variables
+    that tell the provider the data columns to search and the values to find.
+</p>
+<p>
+    For the text expression, define a constant that lists the search columns. Although this
+    expression can contain values as well, the preferred practice is to represent the values with
+    a "?" placeholder. During retrieval, the placeholder is replaced with values from an
+    array. Using "?" as a placeholder ensures that the search specification is generated by binding
+    rather than by SQL compilation. This practice eliminates the possibility of malicious SQL
+    injection. For example:
+</p>
+<pre>
+    // Defines the text expression
+    &#64;SuppressLint("InlinedApi")
+    private static final String SELECTION =
+            Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
+            Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
+            Contacts.DISPLAY_NAME + " LIKE ?";
+    // Defines a variable for the search string
+    private String mSearchString;
+    // Defines the array to hold values that replace the ?
+    private String[] mSelectionArgs = { mSearchString };
+</pre>
+<h3 id="OnItemClick">Define the onItemClick() method</h3>
+<p>
+    In a previous section, you set the item click listener for the {@link android.widget.ListView}.
+    Now implement the action for the listener by defining the method
+    {@link android.widget.AdapterView.OnItemClickListener#onItemClick
+    AdapterView.OnItemClickListener.onItemClick()}:
+</p>
+<pre>
+    &#64;Override
+    public void onItemClick(
+        AdapterView&lt;?&gt; parent, View item, int position, long rowID) {
+        // Get the Cursor
+        Cursor cursor = parent.getAdapter().getCursor();
+        // Move to the selected contact
+        cursor.moveToPosition(position);
+        // Get the _ID value
+        mContactId = getLong(CONTACT_ID_INDEX);
+        // Get the selected LOOKUP KEY
+        mContactKey = getString(CONTACT_KEY_INDEX);
+        // Create the contact's content Uri
+        mContactUri = Contacts.getLookupUri(mContactId, mContactKey);
+        /*
+         * You can use mContactUri as the content URI for retrieving
+         * the details for a contact.
+         */
+    }
+</pre>
+<h3 id="InitializeLoader">Initialize the loader</h3>
+<p>
+    Since you're using a {@link android.support.v4.content.CursorLoader} to retrieve data,
+    you must initialize the background thread and other variables that control asynchronous
+    retrieval. Do the initialization in
+    {@link android.support.v4.app.Fragment#onActivityCreated onActivityCreated()}, which
+    is invoked immediately before the {@link android.support.v4.app.Fragment} UI appears, as
+    shown in the following example:
+</p>
+<pre>
+public class ContactsFragment extends Fragment implements
+        LoaderManager.LoaderCallbacks&lt;Cursor&gt; {
+    ...
+    // Called just before the Fragment displays its UI
+    &#64;Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        // Always call the super method first
+        super.onActivityCreated(savedInstanceState);
+        ...
+        // Initializes the loader
+        getLoaderManager().initLoader(0, null, this);
+</pre>
+<h3 id="OnCreateLoader">Implement onCreateLoader()</h3>
+<p>
+    Implement the method
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
+    which is called by the loader framework immediately after you call
+    {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
+<p>
+    In {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
+    set up the search string pattern. To make a string into a pattern, insert "%"
+    (percent) characters to represent a sequence of zero or more characters, or "_" (underscore)
+    characters to represent a single character, or both. For example, the pattern "%Jefferson%"
+    would match both "Thomas Jefferson" and "Jefferson Davis".
+</p>
+<p>
+    Return a new {@link android.support.v4.content.CursorLoader} from the method. For the content
+    URI, use {@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}.
+    This URI refers to the entire table, as shown in the following example:
+</p>
+<pre>
+    ...
+    &#64;Override
+    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
+        /*
+         * Makes search string into pattern and
+         * stores it in the selection array
+         */
+        mSelectionArgs[0] = "%" + mSearchString + "%";
+        // Starts the query
+        return new CursorLoader(
+                getActivity(),
+                Contacts.CONTENT_URI,
+                PROJECTION,
+                SELECTION,
+                mSelectionArgs,
+                null
+        );
+    }
+</pre>
+<h3 id="FinishedReset">Implement onLoadFinished() and onLoaderReset()</h3>
+<p>
+    Implement the
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+    method. The loader framework calls
+    {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+    when the Contacts Provider returns the results of the query. In this method, put the
+    result {@link android.database.Cursor} in the
+    {@link android.support.v4.widget.SimpleCursorAdapter}. This automatically updates the
+    {@link android.widget.ListView} with the search results:
+</p>
+<pre>
+    public void onLoadFinished(Loader&lt;Cursor&gt; loader, Cursor cursor) {
+        // Put the result Cursor in the adapter for the ListView
+        mCursorAdapter.swapCursor(cursor);
+    }
+</pre>
+<p>
+    The method {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset
+    onLoaderReset()} is invoked when the loader framework detects that the
+    result {@link android.database.Cursor} contains stale data. Delete the
+    {@link android.support.v4.widget.SimpleCursorAdapter} reference to the existing
+    {@link android.database.Cursor}. If you don't, the loader framework will not
+    recycle the {@link android.database.Cursor}, which causes a memory leak. For example:
+</p>
+<pre>
+    &#64;Override
+    public void onLoaderReset(Loader&lt;Cursor&gt; loader) {
+        // Delete the reference to the existing Cursor
+        mCursorAdapter.swapCursor(null);
+
+    }
+</pre>
+
+<p>
+    You now have the key pieces of an app that matches a search string to contact names and returns
+    the result in a {@link android.widget.ListView}. The user can click a contact name to select it.
+    This triggers a listener, in which you can work further with the contact's data. For example,
+    you can retrieve the contact's details. To learn how to do this, continue with the next
+    lesson, <a href="#retrieve-details.html">Retrieving Details for a Contact</a>.
+</p>
+<p>
+    To learn more about search user interfaces, read the API guide
+    <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.
+</p>
+<p>
+    The remaining sections in this lesson demonstrate other ways of finding contacts in the
+    Contacts Provider.
+</p>
+<h2 id="TypeMatch">Match a Contact By a Specific Type of Data</h2>
+<p>
+    This technique allows you to specify the type of data you want to match. Retrieving
+    by name is a specific example of this type of query, but you can also do it for any of the types
+    of detail data associated with a contact. For example, you can retrieve contacts that have a
+    specific postal code; in this case, the search string has to match data stored in a postal code
+    row.
+</p>
+<p>
+    To implement this type of retrieval, first implement the following code, as listed in
+    previous sections:
+</p>
+<ul>
+    <li>
+        Request Permission to Read the Provider.
+    </li>
+    <li>
+        Define ListView and item layouts.
+    </li>
+    <li>
+        Define a Fragment that displays the list of contacts.
+    </li>
+    <li>
+        Define global variables.
+    </li>
+    <li>
+        Initialize the Fragment.
+    </li>
+    <li>
+        Set up the CursorAdapter for the ListView.
+    </li>
+    <li>
+        Set the selected contact listener.
+    </li>
+    <li>
+        Define constants for the Cursor column indexes.
+        <p>
+            Although you're retrieving data from a different table, the order of the columns in
+            the projection is the same, so you can use the same indexes for the Cursor.
+        </p>
+    </li>
+    <li>
+        Define the onItemClick() method.
+    </li>
+    <li>
+        Initialize the loader.
+    </li>
+    <li>
+
+        Implement onLoadFinished() and onLoaderReset().
+    </li>
+</ul>
+<p>
+    The following steps show you the additional code you need to match a search string to
+    a particular type of detail data and display the results.
+</p>
+<h3>Choose the data type and table</h3>
+<p>
+    To search for a particular type of detail data, you have to know the custom MIME type value
+    for the data type. Each data type has a unique MIME type
+    value defined by a constant <code>CONTENT_ITEM_TYPE</code> in the subclass of
+    {@link android.provider.ContactsContract.CommonDataKinds} associated with the data type.
+    The subclasses have names that indicate their data type; for example, the subclass for email
+    data is {@link android.provider.ContactsContract.CommonDataKinds.Email}, and the custom MIME
+    type for email data is defined by the constant
+    {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+    Email.CONTENT_ITEM_TYPE}.
+</p>
+<p>
+    Use the {@link android.provider.ContactsContract.Data} table for your search. All of the
+    constants you need for your projection, selection clause, and sort order are defined in or
+    inherited by this table.
+</p>
+<h3 id="SpecificProjection">Define a projection</h3>
+<p>
+    To define a projection, choose one or more of the columns defined in
+    {@link android.provider.ContactsContract.Data} or the classes from which it inherits. The
+    Contacts Provider does an implicit join between {@link android.provider.ContactsContract.Data}
+    and other tables before it returns rows. For example:
+</p>
+<pre>
+    &#64;SuppressLint("InlinedApi")
+    private static final String[] PROJECTION =
+        {
+            /*
+             * The detail data row ID. To make a ListView work,
+             * this column is required.
+             */
+            Data._ID,
+            // The primary display name
+            Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.HONEYCOMB ?
+                    Data.DISPLAY_NAME_PRIMARY :
+                    Data.DISPLAY_NAME,
+            // The contact's _ID, to construct a content URI
+            Data.CONTACT_ID
+            // The contact's LOOKUP_KEY, to construct a content URI
+            Data.LOOKUP_KEY (a permanent link to the contact
+        };
+</pre>
+<h3 id="SpecificCriteria">Define search criteria</h3>
+<p>
+    To search for a string within a particular type of data, construct a selection clause from
+    the following:
+</p>
+<ul>
+    <li>
+        The name of the column that contains your search string. This name varies by data type,
+        so you need to find the subclass of
+        {@link android.provider.ContactsContract.CommonDataKinds} that corresponds to the data type
+        and then choose the column name from that subclass. For example, to search for
+        email addresses, use the column
+        {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS Email.ADDRESS}.
+    </li>
+    <li>
+        The search string itself, represented as the "?" character in the selection clause.
+    </li>
+    <li>
+        The name of the column that contains the custom MIME type value. This name is always
+        {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
+    </li>
+    <li>
+        The custom MIME type value for the data type. As described previously, this is the constant
+        <code>CONTENT_ITEM_TYPE</code> in the
+        {@link android.provider.ContactsContract.CommonDataKinds} subclass. For example, the MIME
+        type value for email data is
+        {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+        Email.CONTENT_ITEM_TYPE}. Enclose the value in single quotes by concatenating a
+        "<code>'</code>" (single quote) character to the start and end of the constant; otherwise,
+        the provider interprets the value as a variable name rather than as a string value.
+        You don't need to use a placeholder for this value, because you're using a constant
+        rather than a user-supplied value.
+    </li>
+</ul>
+<p>
+    For example:
+</p>
+<pre>
+    /*
+     * Constructs search criteria from the search string
+     * and email MIME type
+     */
+    private static final String SELECTION =
+            /*
+             * Searches for an email address
+             * that matches the search string
+             */
+            Email.ADDRESS + " LIKE ? " + "AND " +
+            /*
+             * Searches for a MIME type that matches
+             * the value of the constant
+             * Email.CONTENT_ITEM_TYPE. Note the
+             * single quotes surrounding Email.CONTENT_ITEM_TYPE.
+             */
+            Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
+</pre>
+<p>
+    Next, define variables to contain the selection argument:
+</p>
+<pre>
+    String mSearchString;
+    String[] mSelectionArgs = { "" };
+</pre>
+<h3 id="SpecificLoader">Implement onCreateLoader()</h3>
+<p>
+    Now that you've specified the data you want and how to find it, define a query in your
+    implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
+    onCreateLoader()}. Return a new {@link android.support.v4.content.CursorLoader} from this
+    method, using your projection, selection text expression, and selection array as
+    arguments. For a content URI, use
+    {@link android.provider.ContactsContract.Data#CONTENT_URI Data.CONTENT_URI}. For example:
+</p>
+<pre>
+    &#64;Override
+    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
+        // OPTIONAL: Makes search string into pattern
+        mSearchString = "%" + mSearchString + "%";
+        // Puts the search string into the selection criteria
+        mSelectionArgs[0] = mSearchString;
+        // Starts the query
+        return new CursorLoader(
+                getActivity(),
+                Data.CONTENT_URI,
+                PROJECTION,
+                SELECTION,
+                mSelectionArgs,
+                null
+        );
+    }
+</pre>
+<p>
+    These code snippets are the basis of a simple reverse lookup based on a specific type of detail
+    data. This is the best technique to use if your app focuses on a particular type of data, such
+    as emails, and you want allow users to get the names associated with a piece of data.
+</p>
+<h2 id="GeneralMatch">Match a Contact By Any Type of Data</h2>
+<p>
+    Retrieving a contact based on any type of data returns contacts if any of their data matches a
+    the search string, including name, email address, postal address, phone number, and so forth.
+    This results in a broad set of search results. For example, if the search string
+    is "Doe", then searching for any data type returns the contact "John Doe"; it also returns
+    contacts who live on "Doe Street".
+</p>
+<p>
+    To implement this type of retrieval, first implement the following code, as listed in
+    previous sections:
+</p>
+<ul>
+    <li>
+        Request Permission to Read the Provider.
+    </li>
+    <li>
+        Define ListView and item layouts.
+    </li>
+    <li>
+    <li>
+        Define a Fragment that displays the list of contacts.
+    </li>
+    <li>
+        Define global variables.
+    </li>
+    <li>
+        Initialize the Fragment.
+    </li>
+    <li>
+        Set up the CursorAdapter for the ListView.
+    </li>
+    <li>
+        Set the selected contact listener.
+    </li>
+    <li>
+        Define a projection.
+    </li>
+    <li>
+        Define constants for the Cursor column indexes.
+        <p>
+            For this type of retrieval, you're using the same table you used in the section
+            <a href="#NameMatch">Match a Contact by Name and List the Results</a>. Use the
+            same column indexes as well.
+        </p>
+    </li>
+    <li>
+        Define the onItemClick() method.
+    </li>
+    <li>
+        Initialize the loader.
+    </li>
+    <li>
+
+        Implement onLoadFinished() and onLoaderReset().
+    </li>
+</ul>
+<p>
+    The following steps show you the additional code you need to match a search string to
+    any type of data and display the results.
+</p>
+<h3 id="NoSelection">Remove selection criteria</h3>
+<p>
+    Don't define the <code>SELECTION</code> constants or the <code>mSelectionArgs</code> variable.
+    These aren't used in this type of retrieval.
+</p>
+<h3 id="CreateLoaderAny">Implement onCreateLoader()</h3>
+<p>
+    Implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
+    onCreateLoader()} method, returning a new {@link android.support.v4.content.CursorLoader}.
+    You don't need to convert the search string into a pattern, because the Contacts Provider does
+    that automatically. Use
+    {@link android.provider.ContactsContract.Contacts#CONTENT_FILTER_URI
+    Contacts.CONTENT_FILTER_URI} as the base URI, and append your search string to it by calling
+    {@link android.net.Uri#withAppendedPath Uri.withAppendedPath()}. Using this URI
+    automatically triggers searching for any data type, as shown in the following example:
+</p>
+<pre>
+    &#64;Override
+    public Loader&lt;Cursor&gt; onCreateLoader(int loaderId, Bundle args) {
+        /*
+         * Appends the search string to the base URI. Always
+         * encode search strings to ensure they're in proper
+         * format.
+         */
+        Uri contentUri = Uri.withAppendedPath(
+                Contacts.CONTENT_FILTER_URI,
+                Uri.encode(mSearchString));
+        // Starts the query
+        return new CursorLoader(
+                getActivity(),
+                contentUri,
+                PROJECTION,
+                null,
+                null,
+                null
+        );
+    }
+</pre>
+<p>
+    These code snippets are the basis of an app that does a broad search of the Contacts Provider.
+    The technique is useful for apps that want to implement functionality similar to the
+    People app's contact list screen.
+</p>
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 417ec5b..b1608c3 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -3,10 +3,6 @@
 parent.link=index.html
 
 trainingnavtop=true
-next.title=Displaying Bitmaps in Your UI
-next.link=display-bitmap.html
-previous.title=Processing Bitmaps Off the UI Thread
-previous.link=process-bitmap.html
 
 @jd:body
 
diff --git a/docs/html/training/displaying-bitmaps/display-bitmap.jd b/docs/html/training/displaying-bitmaps/display-bitmap.jd
index 4572c42..ed1836c 100644
--- a/docs/html/training/displaying-bitmaps/display-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/display-bitmap.jd
@@ -3,8 +3,6 @@
 parent.link=index.html
 
 trainingnavtop=true
-previous.title=Caching Bitmaps
-previous.link=cache-bitmap.html
 
 @jd:body
 
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index b91172b..857edee 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -1,9 +1,8 @@
 page.title=Displaying Bitmaps Efficiently
+page.tags="bitmaps","images","graphics"
 
 trainingnavtop=true
 startpage=true
-next.title=Loading Large Bitmaps Efficiently
-next.link=load-bitmap.html
 
 @jd:body
 
@@ -26,7 +25,7 @@
 </div>
 </div>
 
-<p>This class covers some common techniques for processing and loading {@link
+<p>Learn how to use common techniques to process and load {@link
 android.graphics.Bitmap} objects in a way that keeps your user interface (UI) components responsive
 and avoids exceeding your application memory limit. If you're not careful, bitmaps can quickly
 consume your available memory budget leading to an application crash due to the dreaded
@@ -70,6 +69,9 @@
     <dd>This lesson walks you through using a memory and disk bitmap cache to improve the
     responsiveness and fluidity of your UI when loading multiple bitmaps.</dd>
 
+  <dt><b><a href="manage-memory.html">Managing Bitmap Memory</a></b></dt>
+    <dd>This lesson explains how to manage bitmap memory to maximize your app's performance.</dd>
+
   <dt><b><a href="display-bitmap.html">Displaying Bitmaps in Your UI</a></b></dt>
     <dd>This lesson brings everything together, showing you how to load multiple bitmaps into
     components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView}
diff --git a/docs/html/training/displaying-bitmaps/load-bitmap.jd b/docs/html/training/displaying-bitmaps/load-bitmap.jd
index 283f272..633ffd2 100644
--- a/docs/html/training/displaying-bitmaps/load-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/load-bitmap.jd
@@ -3,8 +3,6 @@
 parent.link=index.html
 
 trainingnavtop=true
-next.title=Processing Bitmaps Off the UI Thread
-next.link=process-bitmap.html
 
 @jd:body
 
@@ -167,4 +165,4 @@
 <p>You can follow a similar process to decode bitmaps from other sources, by substituting the
 appropriate {@link
 android.graphics.BitmapFactory#decodeByteArray(byte[],int,int,android.graphics.BitmapFactory.Options)
-BitmapFactory.decode*} method as needed.</p>
\ No newline at end of file
+BitmapFactory.decode*} method as needed.</p>
diff --git a/docs/html/training/displaying-bitmaps/manage-memory.jd b/docs/html/training/displaying-bitmaps/manage-memory.jd
new file mode 100644
index 0000000..60ac2e6
--- /dev/null
+++ b/docs/html/training/displaying-bitmaps/manage-memory.jd
@@ -0,0 +1,297 @@
+page.title=Managing Bitmap Memory
+parent.title=Displaying Bitmaps Efficiently
+parent.link=index.html
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#recycle">Manage Memory on Android 2.3.3 and Lower</a></li>
+  <li><a href="#inBitmap">Manage Memory on Android 3.0 and Higher</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html">Memory Analysis for Android Applications</a> blog post</li>
+  <li><a href="http://www.google.com/events/io/2011/sessions/memory-management-for-android-apps.html">Memory management for Android Apps</a> Google I/O presentation</li>
+  <li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
+  <li><a href="{@docRoot}design/building-blocks/grid-lists.html">Android Design: Grid Lists</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/BitmapFun.zip" class="button">Download the sample</a>
+  <p class="filename">BitmapFun.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>In addition to the steps described in <a href="cache-bitmap.html">Caching Bitmaps</a>,
+there are  specific things you can do to facilitate garbage collection
+and bitmap reuse. The recommended strategy depends on which version(s)
+of Android you are targeting. The {@code BitmapFun} sample app included with
+this class shows you how to design your app to work efficiently across
+different versions of Android.</p>
+
+<p>To set the stage for this lesson, here is how Android's management of
+bitmap memory has evolved:</p>
+<ul> 
+  <li>
+On Android Android 2.2 (API level 8) and lower, when garbage 
+collection occurs, your app's threads get stopped. This causes a lag that
+can degrade performance. 
+<strong>Android 2.3 adds concurrent garbage collection, which means that
+the memory is reclaimed soon after a bitmap is no longer referenced.</strong>
+</li>
+
+  <li>On Android 2.3.3 (API level 10) and lower, the backing pixel data for a
+bitmap is stored in native memory. It is separate from the bitmap itself,
+which is stored in the Dalvik heap. The pixel data in native memory is
+not released in a predictable manner, potentially causing an application
+to briefly exceed its memory limits and crash.
+<strong>As of Android 3.0 (API Level 11), the pixel data is stored on the
+Dalvik heap along with the associated bitmap.</strong></li>
+
+</ul>
+
+<p>The following sections describe how to optimize bitmap memory
+management for different Android versions.</p>
+
+<h2 id="recycle">Manage Memory on Android 2.3.3 and Lower</h2>
+
+<p>On Android 2.3.3 (API level 10) and lower, using 
+{@link android.graphics.Bitmap#recycle recycle()}
+is recommended. If you're displaying large amounts of bitmap data in your app,
+you're likely to run into
+{@link java.lang.OutOfMemoryError} errors. The
+{@link android.graphics.Bitmap#recycle recycle()} method allows an app
+to reclaim memory as soon as possible.</p>
+
+<p class="note"><strong>Caution:</strong> You should use
+{@link android.graphics.Bitmap#recycle recycle()} only when you are sure that the
+bitmap is no longer being used. If you call {@link android.graphics.Bitmap#recycle recycle()}
+and later attempt to draw the bitmap, you will get the error:
+{@code &quot;Canvas: trying to use a recycled bitmap&quot;}.</p>
+
+<p>The following code snippet gives an example of calling
+{@link android.graphics.Bitmap#recycle recycle()}. It uses reference counting
+(in the variables {@code mDisplayRefCount} and {@code mCacheRefCount}) to track 
+whether a bitmap is currently being displayed or in the cache. The
+code recycles the bitmap when these conditions are met:</p>
+
+<ul>
+<li>The reference count for both {@code mDisplayRefCount} and 
+{@code mCacheRefCount} is 0.</li>
+<li>The bitmap is not {@code null}, and it hasn't been recycled yet.</li>
+</ul>
+
+<pre>private int mCacheRefCount = 0;
+private int mDisplayRefCount = 0;
+...
+// Notify the drawable that the displayed state has changed.
+// Keep a count to determine when the drawable is no longer displayed.
+public void setIsDisplayed(boolean isDisplayed) {
+    synchronized (this) {
+        if (isDisplayed) {
+            mDisplayRefCount++;
+            mHasBeenDisplayed = true;
+        } else {
+            mDisplayRefCount--;
+        }
+    }
+    // Check to see if recycle() can be called.
+    checkState();
+}
+
+// Notify the drawable that the cache state has changed.
+// Keep a count to determine when the drawable is no longer being cached.
+public void setIsCached(boolean isCached) {
+    synchronized (this) {
+        if (isCached) {
+            mCacheRefCount++;
+        } else {
+            mCacheRefCount--;
+        }
+    }
+    // Check to see if recycle() can be called.
+    checkState();
+}
+
+private synchronized void checkState() {
+    // If the drawable cache and display ref counts = 0, and this drawable
+    // has been displayed, then recycle.
+    if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
+            && hasValidBitmap()) {
+        getBitmap().recycle();
+    }
+}
+
+private synchronized boolean hasValidBitmap() {
+    Bitmap bitmap = getBitmap();
+    return bitmap != null && !bitmap.isRecycled();
+}</pre>
+
+<h2 id="inBitmap">Manage Memory on Android 3.0 and Higher</h2>
+
+<p>Android 3.0 (API Level 11) introduces the
+{@link android.graphics.BitmapFactory.Options#inBitmap BitmapFactory.Options.inBitmap}
+field. If this option is set, decode methods that take the 
+{@link android.graphics.BitmapFactory.Options Options} object
+will attempt to reuse an existing bitmap when loading content. This means
+that the bitmap's memory is reused, resulting in improved performance, and
+removing both memory allocation and de-allocation. There are some caveats in using
+{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
+<ul>
+  <li>The reused bitmap must be of the same size as the source content (to make
+sure that the same amount of memory is used), and in JPEG or PNG format
+(whether as a resource or as a stream).</li>
+
+
+<li>The {@link android.graphics.Bitmap.Config configuration} of the reused bitmap
+overrides the setting of
+{@link android.graphics.BitmapFactory.Options#inPreferredConfig}, if set. </li>
+
+  <li>You should always use the returned bitmap of the decode method,
+because you can't assume that reusing the bitmap worked (for example, if there is
+a size mismatch).</li>
+
+<h3>Save a bitmap for later use</h3>
+
+<p>The following snippet demonstrates how an existing bitmap is stored for possible
+later use in the sample app. When an app is running on Android 3.0 or higher and 
+a bitmap is evicted from the {@link android.util.LruCache},
+a soft reference to the bitmap is placed
+in a {@link java.util.HashSet}, for possible reuse later with
+{@link android.graphics.BitmapFactory.Options#inBitmap}:
+
+<pre>HashSet&lt;SoftReference&lt;Bitmap&gt;&gt; mReusableBitmaps;
+private LruCache&lt;String, BitmapDrawable&gt; mMemoryCache;
+
+// If you're running on Honeycomb or newer, create
+// a HashSet of references to reusable bitmaps.
+if (Utils.hasHoneycomb()) {
+    mReusableBitmaps = new HashSet&lt;SoftReference&lt;Bitmap&gt;&gt;();
+}
+
+mMemoryCache = new LruCache&lt;String, BitmapDrawable&gt;(mCacheParams.memCacheSize) {
+
+    // Notify the removed entry that is no longer being cached.
+    &#64;Override
+    protected void entryRemoved(boolean evicted, String key,
+            BitmapDrawable oldValue, BitmapDrawable newValue) {
+        if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
+            // The removed entry is a recycling drawable, so notify it
+            // that it has been removed from the memory cache.
+            ((RecyclingBitmapDrawable) oldValue).setIsCached(false);
+        } else {
+            // The removed entry is a standard BitmapDrawable.
+            if (Utils.hasHoneycomb()) {
+                // We're running on Honeycomb or later, so add the bitmap
+                // to a SoftReference set for possible use with inBitmap later.
+                mReusableBitmaps.add
+                        (new SoftReference&lt;Bitmap&gt;(oldValue.getBitmap()));
+            }
+        }
+    }
+....
+}</pre>
+
+
+<h3>Use an existing bitmap</h3>
+<p>In the running app, decoder methods check to see if there is an existing
+bitmap they can use. For example:</p>
+
+<pre>public static Bitmap decodeSampledBitmapFromFile(String filename,
+        int reqWidth, int reqHeight, ImageCache cache) {
+
+    final BitmapFactory.Options options = new BitmapFactory.Options();
+    ...
+    BitmapFactory.decodeFile(filename, options);
+    ...
+
+    // If we're running on Honeycomb or newer, try to use inBitmap.
+    if (Utils.hasHoneycomb()) {
+        addInBitmapOptions(options, cache);
+    }
+    ...
+    return BitmapFactory.decodeFile(filename, options);
+}</pre
+
+<p>The next snippet shows the {@code addInBitmapOptions()} method that is called in the
+above snippet. It looks for an existing bitmap to set as the value for
+{@link android.graphics.BitmapFactory.Options#inBitmap}. Note that this
+method only sets a value for {@link android.graphics.BitmapFactory.Options#inBitmap}
+if it finds a suitable match (your code should never assume that a match will be found):</p>
+
+<pre>private static void addInBitmapOptions(BitmapFactory.Options options,
+        ImageCache cache) {
+    // inBitmap only works with mutable bitmaps, so force the decoder to
+    // return mutable bitmaps.
+    options.inMutable = true;
+
+    if (cache != null) {
+        // Try to find a bitmap to use for inBitmap.
+        Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
+
+        if (inBitmap != null) {
+            // If a suitable bitmap has been found, set it as the value of
+            // inBitmap.
+            options.inBitmap = inBitmap;
+        }
+    }
+}
+
+// This method iterates through the reusable bitmaps, looking for one 
+// to use for inBitmap:
+protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
+        Bitmap bitmap = null;
+
+    if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
+        final Iterator&lt;SoftReference&lt;Bitmap&gt;&gt; iterator
+                = mReusableBitmaps.iterator();
+        Bitmap item;
+
+        while (iterator.hasNext()) {
+            item = iterator.next().get();
+
+            if (null != item && item.isMutable()) {
+                // Check to see it the item can be used for inBitmap.
+                if (canUseForInBitmap(item, options)) {
+                    bitmap = item;
+
+                    // Remove from reusable set so it can't be used again.
+                    iterator.remove();
+                    break;
+                }
+            } else {
+                // Remove from the set if the reference has been cleared.
+                iterator.remove();
+            }
+        }
+    }
+    return bitmap;
+}</pre>
+
+<p>Finally, this method determines whether a candidate bitmap
+satisfies the size criteria to be used for
+{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
+
+<pre>private static boolean canUseForInBitmap(
+        Bitmap candidate, BitmapFactory.Options targetOptions) {
+    int width = targetOptions.outWidth / targetOptions.inSampleSize;
+    int height = targetOptions.outHeight / targetOptions.inSampleSize;
+
+    // Returns true if "candidate" can be used for inBitmap re-use with
+    // "targetOptions".
+    return candidate.getWidth() == width && candidate.getHeight() == height;
+}</pre>
+
+</body>
+</html>
diff --git a/docs/html/training/displaying-bitmaps/process-bitmap.jd b/docs/html/training/displaying-bitmaps/process-bitmap.jd
index d4fcff3..272b8bc 100644
--- a/docs/html/training/displaying-bitmaps/process-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/process-bitmap.jd
@@ -3,10 +3,6 @@
 parent.link=index.html
 
 trainingnavtop=true
-next.title=Caching Bitmaps
-next.link=cache-bitmap.html
-previous.title=Loading Large Bitmaps Efficiently
-previous.link=load-bitmap.html
 
 @jd:body
 
diff --git a/docs/html/training/efficient-downloads/index.jd b/docs/html/training/efficient-downloads/index.jd
index a29be91..2ab93ae 100644
--- a/docs/html/training/efficient-downloads/index.jd
+++ b/docs/html/training/efficient-downloads/index.jd
@@ -1,9 +1,8 @@
 page.title=Transferring Data Without Draining the Battery
+page.tags="battery","network","wireless"
 
 trainingnavtop=true
 startpage=true
-next.title=Optimizing Downloads for Efficient Network Access
-next.link=efficient-network-access.html
 
 @jd:body
 
diff --git a/docs/html/training/gestures/detector.jd b/docs/html/training/gestures/detector.jd
index 06d0e98..65ddb1b 100644
--- a/docs/html/training/gestures/detector.jd
+++ b/docs/html/training/gestures/detector.jd
@@ -25,12 +25,18 @@
    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
 
 </div>
 </div>
diff --git a/docs/html/training/gestures/index.jd b/docs/html/training/gestures/index.jd
index 0191450..16ca7b0 100644
--- a/docs/html/training/gestures/index.jd
+++ b/docs/html/training/gestures/index.jd
@@ -20,12 +20,18 @@
     <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
 
 </div>
 </div>
diff --git a/docs/html/training/gestures/movement.jd b/docs/html/training/gestures/movement.jd
index f2c49d7..fdc1ea4 100644
--- a/docs/html/training/gestures/movement.jd
+++ b/docs/html/training/gestures/movement.jd
@@ -24,12 +24,18 @@
     <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
 
 </div>
 </div>
diff --git a/docs/html/training/gestures/multi.jd b/docs/html/training/gestures/multi.jd
index d4c5b1d..6a0df11 100644
--- a/docs/html/training/gestures/multi.jd
+++ b/docs/html/training/gestures/multi.jd
@@ -25,12 +25,18 @@
    <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
 
 </div>
 </div>
diff --git a/docs/html/training/gestures/scale.jd b/docs/html/training/gestures/scale.jd
index 17e4085..f2e4eb8 100644
--- a/docs/html/training/gestures/scale.jd
+++ b/docs/html/training/gestures/scale.jd
@@ -15,6 +15,7 @@
 <h2>This lesson teaches you to</h2>
 <ol>
   <li><a href="#drag">Drag an Object</a></li>
+  <li><a href="#pan">Drag to Pan</a></li>
   <li><a href="#scale">Use Touch to Perform Scaling</a></li>
 </ol>
 
@@ -25,20 +26,25 @@
     <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
 
 </div>
 </div>
+
 <p>This lesson describes how to use touch gestures to drag and scale on-screen
 objects, using {@link android.view.View#onTouchEvent onTouchEvent()} to intercept
-touch events. Here is the original <a
-href="http://code.google.com/p/android-touchexample/">source code</a>
-for the examples used in this lesson.
+touch events. 
 </p>
 
 <h2 id="drag">Drag an Object</h2>
@@ -128,17 +134,15 @@
         final float x = MotionEventCompat.getX(ev, pointerIndex);
         final float y = MotionEventCompat.getY(ev, pointerIndex);
             
-        // Only move if the ScaleGestureDetector isn't processing a gesture.
-        if (!mScaleDetector.isInProgress()) {
-            // Calculate the distance moved
-            final float dx = x - mLastTouchX;
-            final float dy = y - mLastTouchY;
+        // Calculate the distance moved
+        final float dx = x - mLastTouchX;
+        final float dy = y - mLastTouchY;
 
-            mPosX += dx;
-            mPosY += dy;
+        mPosX += dx;
+        mPosY += dy;
 
-            invalidate();
-        }
+        invalidate();
+
         // Remember this touch position for the next move event
         mLastTouchX = x;
         mLastTouchY = y;
@@ -175,6 +179,88 @@
     return true;
 }</pre>
 
+<h2 id="pan">Drag to Pan</h2>
+
+<p>The previous section showed an example of dragging an object around the screen. Another 
+common scenario is <em>panning</em>, which is when a user's dragging motion causes scrolling 
+in both the x and y axes. The above snippet directly intercepted the {@link android.view.MotionEvent} 
+actions to implement dragging. The snippet in this section takes advantage of the platform's 
+built-in support for common gestures. It overrides 
+{@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in 
+{@link android.view.GestureDetector.SimpleOnGestureListener}.</p>
+
+<p>To provide a little more context, {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} 
+is called when a user is dragging his finger to pan the content. 
+{@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} is only called when 
+a finger is down; as soon as the finger is lifted from the screen, the gesture either ends, 
+or a fling gesture is started (if the finger was moving with some speed just before it was lifted). 
+For more discussion of scrolling vs. flinging, see <a href="scroll.html">Animating a Scroll Gesture</a>.</p>
+
+<p>Here is the snippet for {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()}:
+
+
+<pre>// The current viewport. This rectangle represents the currently visible 
+// chart domain and range. 
+private RectF mCurrentViewport = 
+        new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX);
+
+// The current destination rectangle (in pixel coordinates) into which the 
+// chart data should be drawn.
+private Rect mContentRect;
+
+private final GestureDetector.SimpleOnGestureListener mGestureListener
+            = new GestureDetector.SimpleOnGestureListener() {
+...
+
+&#64;Override
+public boolean onScroll(MotionEvent e1, MotionEvent e2, 
+            float distanceX, float distanceY) {
+    // Scrolling uses math based on the viewport (as opposed to math using pixels).
+    
+    // Pixel offset is the offset in screen pixels, while viewport offset is the
+    // offset within the current viewport. 
+    float viewportOffsetX = distanceX * mCurrentViewport.width() 
+            / mContentRect.width();
+    float viewportOffsetY = -distanceY * mCurrentViewport.height() 
+            / mContentRect.height();
+    ...
+    // Updates the viewport, refreshes the display. 
+    setViewportBottomLeft(
+            mCurrentViewport.left + viewportOffsetX,
+            mCurrentViewport.bottom + viewportOffsetY);
+    ...
+    return true;
+}</pre>
+
+<p>The implementation of {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} 
+scrolls the viewport in response to the touch gesture:</p>
+
+<pre>
+/**
+ * Sets the current viewport (defined by mCurrentViewport) to the given
+ * X and Y positions. Note that the Y value represents the topmost pixel position, 
+ * and thus the bottom of the mCurrentViewport rectangle.
+ */
+private void setViewportBottomLeft(float x, float y) {
+    /*
+     * Constrains within the scroll range. The scroll range is simply the viewport 
+     * extremes (AXIS_X_MAX, etc.) minus the viewport size. For example, if the 
+     * extremes were 0 and 10, and the viewport size was 2, the scroll range would 
+     * be 0 to 8.
+     */
+
+    float curWidth = mCurrentViewport.width();
+    float curHeight = mCurrentViewport.height();
+    x = Math.max(AXIS_X_MIN, Math.min(x, AXIS_X_MAX - curWidth));
+    y = Math.max(AXIS_Y_MIN + curHeight, Math.min(y, AXIS_Y_MAX));
+
+    mCurrentViewport.set(x, y - curHeight, x + curWidth, y);
+
+    // Invalidates the View to update the display.
+    ViewCompat.postInvalidateOnAnimation(this);
+}
+</pre>
+
 <h2 id="scale">Use Touch to Perform Scaling</h2>
 
 <p>As discussed in <a href="detector.html">Detecting Common Gestures</a>,
@@ -191,10 +277,10 @@
 {@link android.view.ScaleGestureDetector.SimpleOnScaleGestureListener} 
 as a helper class that you can extend if you don’t care about all of the reported events.</p>
 
-<p>Here is a snippet that gives you the basic idea of how to perform scaling.
-Here is the original <a
-href="http://code.google.com/p/android-touchexample/">source code</a>
-for the examples.</p>
+
+<h3>Basic scaling example</h3>
+
+<p>Here is a snippet that illustrates the basic ingredients involved in scaling.</p>
 
 <pre>private ScaleGestureDetector mScaleDetector;
 private float mScaleFactor = 1.f;
@@ -238,3 +324,88 @@
         return true;
     }
 }</pre>
+
+
+
+
+<h3>More complex scaling example</h3>
+<p>Here is a more complex example from the {@code InteractiveChart} sample provided with this class. 
+The {@code InteractiveChart} sample supports both scrolling (panning) and scaling with multiple fingers,
+using the {@link android.view.ScaleGestureDetector} "span" 
+({@link android.view.ScaleGestureDetector#getCurrentSpanX getCurrentSpanX/Y}) and 
+"focus" ({@link android.view.ScaleGestureDetector#getFocusX getFocusX/Y}) features:</p>
+
+<pre>&#64;Override
+private RectF mCurrentViewport = 
+        new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX);
+private Rect mContentRect;
+private ScaleGestureDetector mScaleGestureDetector;
+...
+public boolean onTouchEvent(MotionEvent event) {
+    boolean retVal = mScaleGestureDetector.onTouchEvent(event);
+    retVal = mGestureDetector.onTouchEvent(event) || retVal;
+    return retVal || super.onTouchEvent(event);
+}
+
+/**
+ * The scale listener, used for handling multi-finger scale gestures.
+ */
+private final ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener
+        = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+    /**
+     * This is the active focal point in terms of the viewport. Could be a local
+     * variable but kept here to minimize per-frame allocations.
+     */
+    private PointF viewportFocus = new PointF();
+    private float lastSpanX;
+    private float lastSpanY;
+
+    // Detects that new pointers are going down.
+    &#64;Override
+    public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
+        lastSpanX = ScaleGestureDetectorCompat.
+                getCurrentSpanX(scaleGestureDetector);
+        lastSpanY = ScaleGestureDetectorCompat.
+                getCurrentSpanY(scaleGestureDetector);
+        return true;
+    }
+
+    &#64;Override
+    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
+
+        float spanX = ScaleGestureDetectorCompat.
+                getCurrentSpanX(scaleGestureDetector);
+        float spanY = ScaleGestureDetectorCompat.
+                getCurrentSpanY(scaleGestureDetector);
+
+        float newWidth = lastSpanX / spanX * mCurrentViewport.width();
+        float newHeight = lastSpanY / spanY * mCurrentViewport.height();
+
+        float focusX = scaleGestureDetector.getFocusX();
+        float focusY = scaleGestureDetector.getFocusY();
+        // Makes sure that the chart point is within the chart region.
+        // See the sample for the implementation of hitTest().
+        hitTest(scaleGestureDetector.getFocusX(),
+                scaleGestureDetector.getFocusY(),
+                viewportFocus);
+
+        mCurrentViewport.set(
+                viewportFocus.x
+                        - newWidth * (focusX - mContentRect.left)
+                        / mContentRect.width(),
+                viewportFocus.y
+                        - newHeight * (mContentRect.bottom - focusY)
+                        / mContentRect.height(),
+                0,
+                0);
+        mCurrentViewport.right = mCurrentViewport.left + newWidth;
+        mCurrentViewport.bottom = mCurrentViewport.top + newHeight;     
+        ...
+        // Invalidates the View to update the display.
+        ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
+
+        lastSpanX = spanX;
+        lastSpanY = spanY;
+        return true;
+    }
+};</pre>
diff --git a/docs/html/training/gestures/scroll.jd b/docs/html/training/gestures/scroll.jd
index 8576948..3e3aa14 100644
--- a/docs/html/training/gestures/scroll.jd
+++ b/docs/html/training/gestures/scroll.jd
@@ -14,6 +14,7 @@
 <!-- table of contents -->
 <h2>This lesson teaches you to</h2>
 <ol>
+  <li><a href="#term">Understand Scrolling Terminology</a></li>
   <li><a href="#scroll">Implement Touch-Based Scrolling</a></li>
 </ol>
 
@@ -24,12 +25,18 @@
     <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
 
 </div>
 </div>
@@ -45,7 +52,26 @@
 
 <p>You can use scrollers ({@link android.widget.Scroller} or {@link
 android.widget.OverScroller}) to collect the data you need to produce a
-scrolling animation in response to a touch event.</p>
+scrolling animation in response to a touch event. They are similar, but
+{@link android.widget.OverScroller}
+includes methods for indicating to users that they've reached the content edges 
+after a pan or fling gesture. The {@code InteractiveChart} sample 
+uses the {@link android.widget.EdgeEffect} class
+(actually the {@link android.support.v4.widget.EdgeEffectCompat} class)
+to display a "glow" effect when users reach the content edges.</p>
+
+<p class="note"><strong>Note:</strong> We recommend that you
+use {@link android.widget.OverScroller} rather than {@link
+android.widget.Scroller} for scrolling animations.
+{@link android.widget.OverScroller} provides the best backward
+compatibility with older devices.
+<br />
+Also note that you generally only need to use scrollers
+when implementing scrolling yourself. {@link android.widget.ScrollView} and
+{@link android.widget.HorizontalScrollView} do all of this for you if you nest your 
+layout within them.
+</p>
+
 
 <p>A scroller is used  to animate scrolling over time, using platform-standard
 scrolling physics (friction, velocity, etc.). The scroller itself doesn't
@@ -54,101 +80,280 @@
 responsibility to get and apply new coordinates at a rate that will make the
 scrolling animation look smooth.</p>
 
-<p class="note"><strong>Note:</strong> You generally only need to use scrollers
-when implementing scrolling yourself. {@link android.widget.ScrollView} and
-{@link android.widget.HorizontalScrollView} do all this for you do all of this for you if you nest your layout within them.</p>
-
-<h2 id = "scroll">Implement Touch-Based Scrolling</h2>
 
 
-<p>This snippet illustrates the basics of using a scroller. It uses a 
-{@link android.view.GestureDetector}, and overrides the  
-{@link android.view.GestureDetector.SimpleOnGestureListener} methods 
-{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} and 
-{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}. It also 
-overrides {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} 
-to return {@code false} since you don't need to animate a scroll.</p>
+<h2 id="term">Understand Scrolling Terminology</h2>
 
+<p>"Scrolling" is a word that can take on different meanings in Android, depending on the context.</p>
 
-<p>It's common to use scrollers in conjunction with a fling gesture, but they
+<p><strong>Scrolling</strong> is the general process of moving the viewport (that is, the 'window' 
+of content you're looking at). When scrolling is in both the x and y axes, it's called 
+<em>panning</em>. The sample application provided with this class, {@code InteractiveChart}, illustrates 
+two different types of scrolling, dragging and flinging:</p>
+<ul>
+    <li><strong>Dragging</strong> is the type of scrolling that occurs when a user drags her 
+finger across the touch screen. Simple dragging is often implemented by overriding 
+{@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in 
+{@link android.view.GestureDetector.OnGestureListener}. For more discussion of dragging, see 
+<a href="dragging.jd">Dragging and Scaling</a>.</li>
+
+    <li><strong>Flinging</strong> is the type of scrolling that occurs when a user 
+drags and lifts her finger quickly. After the user lifts her finger, you generally 
+want to keep scrolling (moving the viewport), but decelerate until the viewport stops moving. 
+Flinging can be implemented by overriding 
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()} 
+in {@link android.view.GestureDetector.OnGestureListener}, and by using 
+a scroller object. This is the use 
+case that is the topic of this lesson.</li>
+</ul>
+
+<p>It's common to use scroller objects 
+in conjunction with a fling gesture, but they
 can be used in pretty much any context where you want the UI to display
-scrolling in response to a touch event. For example, you could override {@link
-android.view.View#onTouchEvent onTouchEvent()} to process touch events directly,
-and produce a scrolling effect in response to those touch events.</p>
+scrolling in response to a touch event. For example, you could override  
+{@link android.view.View#onTouchEvent onTouchEvent()} to process touch 
+events directly, and produce a scrolling effect or a "snapping to page" animation 
+in response to those touch events.</p>
 
-<pre>
-private OverScroller mScroller = new OverScroller(context);
 
-private GestureDetector.SimpleOnGestureListener mGestureListener
+<h2 id="#scroll">Implement Touch-Based Scrolling</h2> 
+
+<p>This section describes how to use a scroller.
+The snippet shown below comes from the {@code InteractiveChart} sample 
+provided with this class.
+It uses a 
+{@link android.view.GestureDetector}, and overrides the  
+{@link android.view.GestureDetector.SimpleOnGestureListener} method 
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}.
+It uses {@link android.widget.OverScroller} to track the fling gesture.
+If the user reaches the content edges 
+after the fling gesture, the app displays a "glow" effect.
+</p>
+
+<p class="note"><strong>Note:</strong> The {@code InteractiveChart} sample app displays a 
+chart that you can zoom, pan, scroll, and so on. In the following snippet, 
+{@code mContentRect} represents the rectangle coordinates within the view that the chart 
+will be drawn into. At any given time, a subset of the total chart domain and range are drawn 
+into this rectangular area. 
+{@code mCurrentViewport} represents the portion of the chart that is currently 
+visible in the screen. Because pixel offsets are generally treated as integers, 
+{@code mContentRect} is of the type {@link android.graphics.Rect}. Because the 
+graph domain and range are decimal/float values, {@code mCurrentViewport} is of 
+the type {@link android.graphics.RectF}.</p>
+
+<p>The first part of the snippet shows the implementation of 
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}:</p>
+
+<pre>// The current viewport. This rectangle represents the currently visible 
+// chart domain and range. The viewport is the part of the app that the
+// user manipulates via touch gestures.
+private RectF mCurrentViewport = 
+        new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX);
+
+// The current destination rectangle (in pixel coordinates) into which the 
+// chart data should be drawn.
+private Rect mContentRect;
+
+private OverScroller mScroller;
+private RectF mScrollerStartViewport;
+...
+private final GestureDetector.SimpleOnGestureListener mGestureListener
         = new GestureDetector.SimpleOnGestureListener() {
     &#64;Override
     public boolean onDown(MotionEvent e) {
-        // Abort any active scroll animations and invalidate.
+        // Initiates the decay phase of any active edge effects.
+        releaseEdgeEffects();
+        mScrollerStartViewport.set(mCurrentViewport);
+        // Aborts any active scroll animations and invalidates.
         mScroller.forceFinished(true);
-        // There is also a compatibility version: 
-        // ViewCompat.postInvalidateOnAnimation
-        postInvalidateOnAnimation();
+        ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
         return true;
     }
-
-    &#64;Override
-    public boolean onScroll(MotionEvent e1, MotionEvent e2, 
-            float distanceX, float distanceY) {
-        // You don't use a scroller in onScroll because you don't need to animate
-        // a scroll. The scroll occurs instantly in response to touch feedback.
-        return false;
-    }
-
+    ...
     &#64;Override
     public boolean onFling(MotionEvent e1, MotionEvent e2, 
             float velocityX, float velocityY) {
-        // Before flinging, abort the current animation.
-        mScroller.forceFinished(true);
-        // Begin the scroll animation
-        mScroller.fling(
-                // Current scroll position
-                startX,
-                startY,
-                // Velocities, negated for natural touch response
-                (int) -velocityX,
-                (int) -velocityY,
-                // Minimum and maximum scroll positions. The minimum scroll 
-                // position is generally zero and the maximum scroll position 
-                // is generally the content size less the screen size. So if the 
-                // content width is 1000 pixels and the screen width is 200  
-                // pixels, the maximum scroll offset should be 800 pixels.
-                minX, maxX,
-                minY, maxY,
-                // The maximum overscroll bounds. This is useful when using
-                // the EdgeEffect class to draw overscroll "glow" overlays.
-                mContentRect.width() / 2,
-                mContentRect.height() / 2);
-        // Invalidate to trigger computeScroll()
-        postInvalidateOnAnimation();
+        fling((int) -velocityX, (int) -velocityY);
         return true;
     }
 };
 
+private void fling(int velocityX, int velocityY) {
+    // Initiates the decay phase of any active edge effects.
+    releaseEdgeEffects();
+    // Flings use math in pixels (as opposed to math based on the viewport).
+    Point surfaceSize = computeScrollSurfaceSize();
+    mScrollerStartViewport.set(mCurrentViewport);
+    int startX = (int) (surfaceSize.x * (mScrollerStartViewport.left - 
+            AXIS_X_MIN) / (
+            AXIS_X_MAX - AXIS_X_MIN));
+    int startY = (int) (surfaceSize.y * (AXIS_Y_MAX - 
+            mScrollerStartViewport.bottom) / (
+            AXIS_Y_MAX - AXIS_Y_MIN));
+    // Before flinging, aborts the current animation.
+    mScroller.forceFinished(true);
+    // Begins the animation
+    mScroller.fling(
+            // Current scroll position
+            startX,
+            startY,
+            velocityX,
+            velocityY,
+            /*
+             * Minimum and maximum scroll positions. The minimum scroll 
+             * position is generally zero and the maximum scroll position 
+             * is generally the content size less the screen size. So if the 
+             * content width is 1000 pixels and the screen width is 200  
+             * pixels, the maximum scroll offset should be 800 pixels.
+             */
+            0, surfaceSize.x - mContentRect.width(),
+            0, surfaceSize.y - mContentRect.height(),
+            // The edges of the content. This comes into play when using
+            // the EdgeEffect class to draw "glow" overlays.
+            mContentRect.width() / 2,
+            mContentRect.height() / 2);
+    // Invalidates to trigger computeScroll()
+    ViewCompat.postInvalidateOnAnimation(this);
+}</pre>
+
+<p>When {@link android.view.GestureDetector.OnGestureListener#onFling onFling()} calls 
+{@link android.support.v4.view.ViewCompat#postInvalidateOnAnimation postInvalidateOnAnimation()}, 
+it triggers 
+{@link android.view.View#computeScroll computeScroll()} to update the values for x and y. 
+This is typically be done when a view child is animating a scroll using a scroller object, as in this example. </p>
+
+<p>Most views pass the scroller object's x and y position directly to 
+{@link android.view.View#scrollTo scrollTo()}. 
+The following implementation of {@link android.view.View#computeScroll computeScroll()} 
+takes a different approach&mdash;it calls 
+{@link android.widget.OverScroller#computeScrollOffset computeScrollOffset()} to get the current 
+location of x and y. When the criteria for displaying an overscroll "glow" edge effect are met 
+(the display is zoomed in, x or y is out of bounds, and the app isn't already showing an overscroll), 
+the code sets up the overscroll glow effect and calls 
+{@link android.support.v4.view.ViewCompat#postInvalidateOnAnimation postInvalidateOnAnimation()} 
+to trigger an invalidate on the view:</p>
+
+<pre>// Edge effect / overscroll tracking objects.
+private EdgeEffectCompat mEdgeEffectTop;
+private EdgeEffectCompat mEdgeEffectBottom;
+private EdgeEffectCompat mEdgeEffectLeft;
+private EdgeEffectCompat mEdgeEffectRight;
+
+private boolean mEdgeEffectTopActive;
+private boolean mEdgeEffectBottomActive;
+private boolean mEdgeEffectLeftActive;
+private boolean mEdgeEffectRightActive;
+
 &#64;Override
 public void computeScroll() {
     super.computeScroll();
 
-    // Compute the current scroll offsets. If this returns true, then the 
-    // scroll has not yet finished.
+    boolean needsInvalidate = false;
+
+    // The scroller isn't finished, meaning a fling or programmatic pan 
+    // operation is currently active.
     if (mScroller.computeScrollOffset()) {
+        Point surfaceSize = computeScrollSurfaceSize();
         int currX = mScroller.getCurrX();
         int currY = mScroller.getCurrY();
 
-        // Actually render the scrolled viewport, or actually scroll the 
-        // view using View.scrollTo.
+        boolean canScrollX = (mCurrentViewport.left > AXIS_X_MIN
+                || mCurrentViewport.right < AXIS_X_MAX);
+        boolean canScrollY = (mCurrentViewport.top > AXIS_Y_MIN
+                || mCurrentViewport.bottom < AXIS_Y_MAX);
 
-        // If currX or currY are outside the bounds, render the overscroll 
-        // glow using EdgeEffect.
+        /*          
+         * If you are zoomed in and currX or currY is
+         * outside of bounds and you're not already
+         * showing overscroll, then render the overscroll
+         * glow edge effect.
+         */
+        if (canScrollX
+                && currX < 0
+                && mEdgeEffectLeft.isFinished()
+                && !mEdgeEffectLeftActive) {
+            mEdgeEffectLeft.onAbsorb((int) 
+                    OverScrollerCompat.getCurrVelocity(mScroller));
+            mEdgeEffectLeftActive = true;
+            needsInvalidate = true;
+        } else if (canScrollX
+                && currX > (surfaceSize.x - mContentRect.width())
+                && mEdgeEffectRight.isFinished()
+                && !mEdgeEffectRightActive) {
+            mEdgeEffectRight.onAbsorb((int) 
+                    OverScrollerCompat.getCurrVelocity(mScroller));
+            mEdgeEffectRightActive = true;
+            needsInvalidate = true;
+        }
 
-    } else {
-        // The scroll has finished.
-    }
+        if (canScrollY
+                && currY < 0
+                && mEdgeEffectTop.isFinished()
+                && !mEdgeEffectTopActive) {
+            mEdgeEffectTop.onAbsorb((int) 
+                    OverScrollerCompat.getCurrVelocity(mScroller));
+            mEdgeEffectTopActive = true;
+            needsInvalidate = true;
+        } else if (canScrollY
+                && currY > (surfaceSize.y - mContentRect.height())
+                && mEdgeEffectBottom.isFinished()
+                && !mEdgeEffectBottomActive) {
+            mEdgeEffectBottom.onAbsorb((int) 
+                    OverScrollerCompat.getCurrVelocity(mScroller));
+            mEdgeEffectBottomActive = true;
+            needsInvalidate = true;
+        }
+        ...
+    }</pre>
+
+<p>Here is the section of the code that performs the actual zoom:</p>
+
+<pre>// Custom object that is functionally similar to Scroller
+Zoomer mZoomer;
+private PointF mZoomFocalPoint = new PointF();
+...
+
+// If a zoom is in progress (either programmatically or via double
+// touch), performs the zoom.
+if (mZoomer.computeZoom()) {
+    float newWidth = (1f - mZoomer.getCurrZoom()) * 
+            mScrollerStartViewport.width();
+    float newHeight = (1f - mZoomer.getCurrZoom()) * 
+            mScrollerStartViewport.height();
+    float pointWithinViewportX = (mZoomFocalPoint.x - 
+            mScrollerStartViewport.left)
+            / mScrollerStartViewport.width();
+    float pointWithinViewportY = (mZoomFocalPoint.y - 
+            mScrollerStartViewport.top)
+            / mScrollerStartViewport.height();
+    mCurrentViewport.set(
+            mZoomFocalPoint.x - newWidth * pointWithinViewportX,
+            mZoomFocalPoint.y - newHeight * pointWithinViewportY,
+            mZoomFocalPoint.x + newWidth * (1 - pointWithinViewportX),
+            mZoomFocalPoint.y + newHeight * (1 - pointWithinViewportY));
+    constrainViewport();
+    needsInvalidate = true;
+}
+if (needsInvalidate) {
+    ViewCompat.postInvalidateOnAnimation(this);
+}
+</pre>
+
+<p>This is the {@code computeScrollSurfaceSize()} method that's called in the above snippet. It 
+computes the current scrollable surface size, in pixels. For example, if the entire chart area is visible, 
+this is simply the current size of {@code mContentRect}. If the chart is zoomed in 200% in both directions, 
+the returned size will be twice as large horizontally and vertically.</p>
+
+<pre>private Point computeScrollSurfaceSize() {
+    return new Point(
+            (int) (mContentRect.width() * (AXIS_X_MAX - AXIS_X_MIN)
+                    / mCurrentViewport.width()),
+            (int) (mContentRect.height() * (AXIS_Y_MAX - AXIS_Y_MIN)
+                    / mCurrentViewport.height()));
 }</pre>
 
-<p>For another example of scroller usage, see the <a href="http://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/view/ViewPager.java">source code</a> for the 
-{@link android.support.v4.view.ViewPager} class.</p>
+<p>For another example of scroller usage, see the 
+<a href="http://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/view/ViewPager.java">source code</a> for the 
+{@link android.support.v4.view.ViewPager} class. It scrolls in response to flings, 
+and uses scrolling to implement the "snapping to page" animation.</p>
+
diff --git a/docs/html/training/gestures/viewgroup.jd b/docs/html/training/gestures/viewgroup.jd
index 257a5d8..5b32300 100644
--- a/docs/html/training/gestures/viewgroup.jd
+++ b/docs/html/training/gestures/viewgroup.jd
@@ -26,12 +26,19 @@
     <li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
     </li>
     <li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
-    <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
     <li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
     <li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
     <li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
+
 
 </div>
 </div>
diff --git a/docs/html/training/graphics/opengl/index.jd b/docs/html/training/graphics/opengl/index.jd
index 23a734a..cf33d80 100644
--- a/docs/html/training/graphics/opengl/index.jd
+++ b/docs/html/training/graphics/opengl/index.jd
@@ -1,7 +1,6 @@
 page.title=Displaying Graphics with OpenGL ES
+page=tags="open gl","graphics"
 trainingnavtop=true
-next.title=Building an OpenGL ES Environment
-next.link=environment.html
 
 @jd:body
 
diff --git a/docs/html/training/id-auth/authenticate.jd b/docs/html/training/id-auth/authenticate.jd
index 592fe1c..3084bea 100644
--- a/docs/html/training/id-auth/authenticate.jd
+++ b/docs/html/training/id-auth/authenticate.jd
@@ -114,7 +114,7 @@
     new Handler(new OnError()));    // Callback called if an error occurs
 </pre>
 
-<p>In this example, <code>OnTokenAcquired</code> is a class that extends
+<p>In this example, <code>OnTokenAcquired</code> is a class that implements
 {@link android.accounts.AccountManagerCallback}. {@link android.accounts.AccountManager} calls
 {@link android.accounts.AccountManagerCallback#run run()} on <code>OnTokenAcquired</code> with an
 {@link android.accounts.AccountManagerFuture} that contains a {@link android.os.Bundle}. If
@@ -179,7 +179,7 @@
     &#64;Override
     public void run(AccountManagerFuture&lt;Bundle&gt; result) {
         ...
-        Intent launch = (Intent) result.get(AccountManager.KEY_INTENT);
+        Intent launch = (Intent) result.getResult().get(AccountManager.KEY_INTENT);
         if (launch != null) {
             startActivityForResult(launch, 0);
             return;
diff --git a/docs/html/training/implementing-navigation/lateral.jd b/docs/html/training/implementing-navigation/lateral.jd
index b59bab2..c8f57a2 100644
--- a/docs/html/training/implementing-navigation/lateral.jd
+++ b/docs/html/training/implementing-navigation/lateral.jd
@@ -43,7 +43,8 @@
 
 <p>Tabs allow the user to navigate between sibling screens by selecting the appropriate tab indicator available at the top of the display. In Android 3.0 and later, tabs are implemented using the {@link android.app.ActionBar} class, and are generally set up in {@link android.app.Activity#onCreate Activity.onCreate()}. In some cases, such as when horizontal space is limited and/or the number of tabs is large, an appropriate alternate presentation for tabs is a dropdown list (sometimes implemented using a {@link android.widget.Spinner}).</p>
 
-<p>In previous versions of Android, tabs could be implemented using a {@link android.widget.TabWidget} and {@link android.widget.TabHost}. For details, see the <a href="{@docRoot}resources/tutorials/views/hello-tabwidget.html">Hello, Views</a> tutorial.</p>
+<p>In previous versions of Android, tabs could be implemented using a
+{@link android.widget.TabWidget} and {@link android.widget.TabHost}.</p>
 
 <p>As of Android 3.0, however, you should use either {@link android.app.ActionBar#NAVIGATION_MODE_TABS} or {@link android.app.ActionBar#NAVIGATION_MODE_LIST} along with the {@link android.app.ActionBar} class.</p>
 
@@ -131,6 +132,9 @@
     ViewPager mViewPager;
 
     public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_collection_demo);
+
         // ViewPager and its adapters use support library
         // fragments, so use getSupportFragmentManager.
         mDemoCollectionPagerAdapter =
diff --git a/docs/html/training/in-app-billing/list-iab-products.jd b/docs/html/training/in-app-billing/list-iab-products.jd
index 36ff34a..c423fc1 100644
--- a/docs/html/training/in-app-billing/list-iab-products.jd
+++ b/docs/html/training/in-app-billing/list-iab-products.jd
@@ -54,7 +54,7 @@
 <li>The {@code List} argument consists of one or more product IDs (also called SKUs) for the products that you want to query.</li>
 <li>Finally, the {@code QueryInventoryFinishedListener} argument specifies a listener is notified when the query operation has completed and handles the query response.</li>
 </ul>
-If you use the the convenience classes provided in the sample, the classes will handle background thread management for In-app Billing requests, so you can safely make queries from the main thread of your application.
+If you use the convenience classes provided in the sample, the classes will handle background thread management for In-app Billing requests, so you can safely make queries from the main thread of your application.
 </p>
 <p>The following code shows how you can retrieve the details for two products with IDs {@code SKU_APPLE} and {@code SKU_BANANA} that you previously defined in the Developer Console.</p>
 
diff --git a/docs/html/training/in-app-billing/purchase-iab-products.jd b/docs/html/training/in-app-billing/purchase-iab-products.jd
index 7fa77d3..4e6e035 100644
--- a/docs/html/training/in-app-billing/purchase-iab-products.jd
+++ b/docs/html/training/in-app-billing/purchase-iab-products.jd
@@ -104,7 +104,7 @@
 </pre>
 
 <h2 id="Consume">Consume a Purchase</h2>
-<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replensihable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
+<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable.  How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replenishable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
 <p>It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.</p>
 <p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
 <p>To record a purchase consumption, call {@code consumeAsync(Purchase, OnConsumeFinishedListener)} on your {@code IabHelper} instance. The first argument that the method takes is the {@code Purchase} object representing the item to consume. The second argument is a {@code OnConsumeFinishedListener} that is notified when the consumption operation has completed and handles the consumption response from Google Play. It is safe to make this call fom your main thread.</p>
diff --git a/docs/html/training/managing-audio/index.jd b/docs/html/training/managing-audio/index.jd
index 0f7bbfd..3e3bcf0 100644
--- a/docs/html/training/managing-audio/index.jd
+++ b/docs/html/training/managing-audio/index.jd
@@ -1,9 +1,8 @@
 page.title=Managing Audio Playback
+page.tags="audio","media"
 
 trainingnavtop=true
 startpage=true
-next.title=Controlling Your App's Volume and Playback
-next.link=volume-playback.html
 
 @jd:body
 
diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd
index c963a18..a202566 100644
--- a/docs/html/training/monitoring-device-state/battery-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd
@@ -65,9 +65,9 @@
                      status == BatteryManager.BATTERY_STATUS_FULL;
 
 // How are we charging?
-int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
-boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
-boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre>
+int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;</pre>
 
 <p>Typically you should maximize the rate of your background updates in the case where the device is
 connected to an AC charger, reduce the rate if the charge is over USB, and lower it
@@ -105,8 +105,8 @@
                             status == BatteryManager.BATTERY_STATUS_FULL;
     
         int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
-        boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
-        boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;
+        boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+        boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
     }
 }</pre>
 
@@ -119,8 +119,8 @@
 <p>You can find the current battery charge by extracting the current battery level and scale from
 the battery status intent as shown here:</p>
 
-<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
-int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+<pre>int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
 
 float batteryPct = level / (float)scale;</pre>
 
diff --git a/docs/html/training/monitoring-device-state/docking-monitoring.jd b/docs/html/training/monitoring-device-state/docking-monitoring.jd
index 3787a55..5c8bfd6 100644
--- a/docs/html/training/monitoring-device-state/docking-monitoring.jd
+++ b/docs/html/training/monitoring-device-state/docking-monitoring.jd
@@ -79,7 +79,7 @@
 
 <h2 id="MonitorDockState">Monitor for Changes in the Dock State or Type</h2> 
 
-<p>Whenever the the device is docked or undocked, the {@link
+<p>Whenever the device is docked or undocked, the {@link
 android.content.Intent#ACTION_DOCK_EVENT} action is broadcast. To monitor changes in the
 device's dock-state, simply register a broadcast receiver in your application manifest as shown in
 the snippet below:</p>
diff --git a/docs/html/training/multiple-threads/define-runnable.jd b/docs/html/training/multiple-threads/define-runnable.jd
index 17640a9..40853d3 100644
--- a/docs/html/training/multiple-threads/define-runnable.jd
+++ b/docs/html/training/multiple-threads/define-runnable.jd
@@ -98,7 +98,7 @@
         android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
         ...
         /*
-         * Stores the current Thread in the the PhotoTask instance,
+         * Stores the current Thread in the PhotoTask instance,
          * so that the instance
          * can interrupt the Thread.
          */
diff --git a/docs/html/training/notify-user/build-notification.jd b/docs/html/training/notify-user/build-notification.jd
index ba66028..80f2cd5 100644
--- a/docs/html/training/notify-user/build-notification.jd
+++ b/docs/html/training/notify-user/build-notification.jd
@@ -149,12 +149,14 @@
 <p>For example:</p>
 
 <pre>
+NotificationCompat.Builder mBuilder;
+...
 // Sets an ID for the notification
 int mNotificationId = 001;
 // Gets an instance of the NotificationManager service
 NotificationManager mNotifyMgr = 
         (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
 // Builds the notification and issues it.
-mNotifyMgr.notify(mNotificationId, builder.build());
+mNotifyMgr.notify(mNotificationId, mBuilder.build());
 </pre>
 
diff --git a/docs/html/training/sharing/index.jd b/docs/html/training/sharing/index.jd
index c2e8dbc..2aa22b6 100644
--- a/docs/html/training/sharing/index.jd
+++ b/docs/html/training/sharing/index.jd
@@ -1,9 +1,8 @@
 page.title=Sharing Content
+page.tags="intents","share"
 
 trainingnavtop=true
 startpage=true
-next.title=Sending Content to Other Apps
-next.link=send.html
 
 @jd:body
 
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 79980be..7a3f2ca 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -287,6 +287,10 @@
             Caching Bitmaps
           </a>
           </li>
+          <li><a href="<?cs var:toroot ?>training/displaying-bitmaps/manage-memory.html">
+            Managing Bitmap Memory
+          </a>
+          </li>
           <li><a href="<?cs var:toroot ?>training/displaying-bitmaps/display-bitmap.html">
             Displaying Bitmaps in Your UI
           </a></li>
@@ -480,7 +484,37 @@
       </a>
     </div>
     <ul>
-    
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/contacts-provider/index.html"
+             description=
+             "How to use Android's central address book, the Contacts Provider, to
+             display contacts and their details and modify contact information.">
+          Accessing Contacts Data</a>
+        </div>
+        <ul>
+          <li>
+                <a href="<?cs var:toroot ?>training/contacts-provider/retrieve-names.html">
+                Retrieving a List of Contacts
+                </a>
+          </li>
+          <li>
+                <a href="<?cs var:toroot ?>training/contacts-provider/retrieve-details.html">
+                Retrieving Details for a Contact
+                </a>
+          </li>
+          <li>
+                <a href="<?cs var:toroot ?>training/contacts-provider/modify-data.html">
+                Modifying Contacts Using Intents
+                </a>
+          </li>
+          <li>
+                <a href="<?cs var:toroot ?>training/contacts-provider/display-contact-badge.html">
+                Displaying the Quick Contact Badge
+                </a>
+          </li>
+        </ul>
+      </li>
       <li class="nav-section">
         <div class="nav-section-header">
           <a href="<?cs var:toroot ?>training/id-auth/index.html"
@@ -875,7 +909,7 @@
         </ul>
       </li>
     </ul>
-  </li> <!-- end of User Input -->    
+  </li> <!-- end of User Input -->
 
   <li class="nav-section">
     <div class="nav-section-header">
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
index fff7eee..474b9b2 100644
--- a/drm/jni/Android.mk
+++ b/drm/jni/Android.mk
@@ -23,6 +23,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libdrmframework \
+    liblog \
     libutils \
     libandroid_runtime \
     libnativehelper \
@@ -43,4 +44,3 @@
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 9bb90f1..cc7f23f 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -62,6 +62,18 @@
     @SuppressWarnings({"UnusedDeclaration"})
     private int mSurfaceFormat;
 
+    /**
+     * Flag for drawTextRun indicating left-to-right run direction.
+     * @hide
+     */
+    public static final int DIRECTION_LTR = 0;
+    
+    /**
+     * Flag for drawTextRun indicating right-to-left run direction.
+     * @hide
+     */
+    public static final int DIRECTION_RTL = 1;
+
     // Maximum bitmap size as defined in Skia's native code
     // (see SkCanvas.cpp, SkDraw.cpp)
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
@@ -683,8 +695,16 @@
     }
 
     public enum EdgeType {
+
+        /**
+         * Black-and-White: Treat edges by just rounding to nearest pixel boundary
+         */
         BW(0),  //!< treat edges by just rounding to nearest pixel boundary
-        AA(1);  //!< treat edges by rounding-out, since they may be antialiased
+
+        /**
+         * Antialiased: Treat edges by rounding-out, since they may be antialiased
+         */
+        AA(1);
         
         EdgeType(int nativeInt) {
             this.nativeInt = nativeInt;
@@ -703,7 +723,9 @@
      * therefore you can skip making the draw calls).
      *
      * @param rect  the rect to compare with the current clip
-     * @param type  specifies how to treat the edges (BW or antialiased)
+     * @param type  {@link Canvas.EdgeType#AA} if the path should be considered antialiased,
+     *              since that means it may affect a larger area (more pixels) than
+     *              non-antialiased ({@link Canvas.EdgeType#BW}).
      * @return      true if the rect (transformed by the canvas' matrix)
      *              does not intersect with the canvas' clip
      */
@@ -720,10 +742,9 @@
      * (i.e. the bounds of the path intersects, but the path does not).
      *
      * @param path        The path to compare with the current clip
-     * @param type        true if the path should be considered antialiased,
-     *                    since that means it may
-     *                    affect a larger area (more pixels) than
-     *                    non-antialiased.
+     * @param type        {@link Canvas.EdgeType#AA} if the path should be considered antialiased,
+     *                    since that means it may affect a larger area (more pixels) than
+     *                    non-antialiased ({@link Canvas.EdgeType#BW}).
      * @return            true if the path (transformed by the canvas' matrix)
      *                    does not intersect with the canvas' clip
      */
@@ -745,9 +766,9 @@
      *                    current clip
      * @param bottom      The bottom of the rectangle to compare with the
      *                    current clip
-     * @param type        true if the rect should be considered antialiased,
-     *                    since that means it may affect a larger area (more
-     *                    pixels) than non-antialiased.
+     * @param type        {@link Canvas.EdgeType#AA} if the path should be considered antialiased,
+     *                    since that means it may affect a larger area (more pixels) than
+     *                    non-antialiased ({@link Canvas.EdgeType#BW}).
      * @return            true if the rect (transformed by the canvas' matrix)
      *                    does not intersect with the canvas' clip
      */
@@ -1333,7 +1354,8 @@
             (text.length - index - count)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
+                paint.mNativePaint);
     }
 
     /**
@@ -1346,7 +1368,8 @@
      * @param paint The paint used for the text (e.g. color, size, style)
      */
     public void drawText(String text, float x, float y, Paint paint) {
-        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
+                paint.mNativePaint);
     }
 
     /**
@@ -1364,7 +1387,8 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mNativePaint);
+        native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
+                paint.mNativePaint);
     }
 
     /**
@@ -1383,14 +1407,16 @@
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
-            native_drawText(mNativeCanvas, text.toString(), start, end, x, y, paint.mNativePaint);
+            native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
+                            paint.mBidiFlags, paint.mNativePaint);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawText(this, start, end, x, y,
                                                      paint);
         } else {
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
-            native_drawText(mNativeCanvas, buf, 0, end - start, x, y, paint.mNativePaint);
+            native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
+                    paint.mBidiFlags, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1411,11 +1437,13 @@
      *         + count.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
+     * @param dir the run direction, either {@link #DIRECTION_LTR} or
+     *         {@link #DIRECTION_RTL}.
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1426,9 +1454,12 @@
         if ((index | count | text.length - index - count) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown dir: " + dir);
+        }
 
         native_drawTextRun(mNativeCanvas, text, index, count,
-                contextIndex, contextCount, x, y, paint.mNativePaint);
+                contextIndex, contextCount, x, y, dir, paint.mNativePaint);
     }
 
     /**
@@ -1444,11 +1475,12 @@
      *            position can be used for shaping context.
      * @param x the x position at which to draw the text
      * @param y the y position at which to draw the text
+     * @param dir the run direction, either 0 for LTR or 1 for RTL.
      * @param paint the paint
      * @hide
      */
     public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
-            float x, float y, Paint paint) {
+            float x, float y, int dir, Paint paint) {
 
         if (text == null) {
             throw new NullPointerException("text is null");
@@ -1460,20 +1492,22 @@
             throw new IndexOutOfBoundsException();
         }
 
+        int flags = dir == 0 ? 0 : 1;
+
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvas, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, paint.mNativePaint);
+                    contextStart, contextEnd, x, y, flags, paint.mNativePaint);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
-                    contextStart, contextEnd, x, y, paint);
+                    contextStart, contextEnd, x, y, flags, paint);
         } else {
             int contextLen = contextEnd - contextStart;
             int len = end - start;
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
-                    0, contextLen, x, y, paint.mNativePaint);
+                    0, contextLen, x, y, flags, paint.mNativePaint);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1539,7 +1573,8 @@
             throw new ArrayIndexOutOfBoundsException();
         }
         native_drawTextOnPath(mNativeCanvas, text, index, count,
-                              path.ni(), hOffset, vOffset, paint.mNativePaint);
+                              path.ni(), hOffset, vOffset,
+                              paint.mBidiFlags, paint.mNativePaint);
     }
 
     /**
@@ -1558,7 +1593,7 @@
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
         if (text.length() > 0) {
             native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
-                    paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint);
         }
     }
 
@@ -1720,18 +1755,18 @@
     
     private static native void native_drawText(int nativeCanvas, char[] text,
                                                int index, int count, float x,
-                                               float y, int paint);
+                                               float y, int flags, int paint);
     private static native void native_drawText(int nativeCanvas, String text,
                                                int start, int end, float x,
-                                               float y, int paint);
+                                               float y, int flags, int paint);
 
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int paint);
+            float x, float y, int flags, int paint);
 
     private static native void native_drawTextRun(int nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int paint);
+            float x, float y, int flags, int paint);
 
     private static native void native_drawPosText(int nativeCanvas,
                                                   char[] text, int index,
@@ -1744,13 +1779,13 @@
                                                      char[] text, int index,
                                                      int count, int path,
                                                      float hOffset,
-                                                     float vOffset,
+                                                     float vOffset, int bidiFlags,
                                                      int paint);
     private static native void native_drawTextOnPath(int nativeCanvas,
                                                      String text, int path,
                                                      float hOffset, 
                                                      float vOffset, 
-                                                     int paint);
+                                                     int flags, int paint);
     private static native void native_drawPicture(int nativeCanvas,
                                                   int nativePicture);
     private static native void finalizer(int nativeCanvas);
diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java
index 4f16dc4..2bdecce 100644
--- a/graphics/java/android/graphics/DashPathEffect.java
+++ b/graphics/java/android/graphics/DashPathEffect.java
@@ -26,7 +26,7 @@
      * controls the length of the dashes. The paint's strokeWidth controls the
      * thickness of the dashes.
      * Note: this patheffect only affects drawing with the paint's style is set
-     * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
+     * to STROKE or FILL_AND_STROKE. It is ignored if the drawing is done with
      * style == FILL.
      * @param intervals array of ON and OFF distances
      * @param phase offset into the intervals array
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 8da20f2..1485d8d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -69,6 +69,11 @@
      */
     public int shadowColor;
 
+    /**
+     * @hide
+     */
+    public  int         mBidiFlags = BIDI_DEFAULT_LTR;
+    
     static final Style[] sStyleArray = {
         Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
     };
@@ -115,6 +120,74 @@
     public static final int HINTING_ON = 0x1;
 
     /**
+     * Bidi flag to set LTR paragraph direction.
+     * 
+     * @hide
+     */
+    public static final int BIDI_LTR = 0x0;
+
+    /**
+     * Bidi flag to set RTL paragraph direction.
+     * 
+     * @hide
+     */
+    public static final int BIDI_RTL = 0x1;
+
+    /**
+     * Bidi flag to detect paragraph direction via heuristics, defaulting to
+     * LTR.
+     * 
+     * @hide
+     */
+    public static final int BIDI_DEFAULT_LTR = 0x2;
+
+    /**
+     * Bidi flag to detect paragraph direction via heuristics, defaulting to
+     * RTL.
+     * 
+     * @hide
+     */
+    public static final int BIDI_DEFAULT_RTL = 0x3;
+
+    /**
+     * Bidi flag to override direction to all LTR (ignore bidi).
+     * 
+     * @hide
+     */
+    public static final int BIDI_FORCE_LTR = 0x4;
+
+    /**
+     * Bidi flag to override direction to all RTL (ignore bidi).
+     * 
+     * @hide
+     */
+    public static final int BIDI_FORCE_RTL = 0x5;
+
+    /**
+     * Maximum Bidi flag value.
+     * @hide
+     */
+    private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL;
+
+    /**
+     * Mask for bidi flags.
+     * @hide
+     */
+    private static final int BIDI_FLAG_MASK = 0x7;
+
+    /**
+     * Flag for getTextRunAdvances indicating left-to-right run direction.
+     * @hide
+     */
+    public static final int DIRECTION_LTR = 0;
+
+    /**
+     * Flag for getTextRunAdvances indicating right-to-left run direction.
+     * @hide
+     */
+    public static final int DIRECTION_RTL = 1;
+
+    /**
      * Option for getTextRunCursor to compute the valid cursor after
      * offset or the limit of the context, whichever is less.
      * @hide
@@ -322,6 +395,7 @@
         shadowRadius = 0;
         shadowColor = 0;
 
+        mBidiFlags = BIDI_DEFAULT_LTR;
         setTextLocale(Locale.getDefault());
     }
     
@@ -361,6 +435,7 @@
         shadowRadius = paint.shadowRadius;
         shadowColor = paint.shadowColor;
 
+        mBidiFlags = paint.mBidiFlags;
         mLocale = paint.mLocale;
     }
 
@@ -377,6 +452,29 @@
     }
 
     /**
+     * Return the bidi flags on the paint.
+     * 
+     * @return the bidi flags on the paint
+     * @hide
+     */
+    public int getBidiFlags() {
+        return mBidiFlags;
+    }
+
+    /**
+     * Set the bidi flags on the paint.
+     * @hide
+     */
+    public void setBidiFlags(int flags) {
+        // only flag value is the 3-bit BIDI control setting
+        flags &= BIDI_FLAG_MASK;
+        if (flags > BIDI_MAX_FLAG_VALUE) {
+            throw new IllegalArgumentException("unknown bidi flag: " + flags);
+        }
+        mBidiFlags = flags;
+    }
+
+    /**
      * Return the paint's flags. Use the Flag enum to test flag values.
      * 
      * @return the paint's flags (see enums ending in _Flag for bit masks)
@@ -1197,17 +1295,17 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, index, count));
+            return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, index, count);
+        float w = native_measureText(text, index, count, mBidiFlags);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(char[] text, int index, int count);
+    private native float native_measureText(char[] text, int index, int count, int bidiFlags);
     
     /**
      * Return the width of the text.
@@ -1229,17 +1327,17 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, start, end));
+            return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, start, end);
+        float w = native_measureText(text, start, end, mBidiFlags);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(String text, int start, int end);
+    private native float native_measureText(String text, int start, int end, int bidiFlags);
     
     /**
      * Return the width of the text.
@@ -1257,16 +1355,16 @@
         }
 
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text));
+            return (float) Math.ceil(native_measureText(text, mBidiFlags));
         }
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text);
+        float w = native_measureText(text, mBidiFlags);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(String text);
+    private native float native_measureText(String text, int bidiFlags);
     
     /**
      * Return the width of the text.
@@ -1333,12 +1431,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(text, index, count, maxWidth, measuredWidth);
+            return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(text, index, count, maxWidth*mCompatScaling,
+        int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
                 measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
@@ -1346,7 +1444,7 @@
     }
 
     private native int native_breakText(char[] text, int index, int count,
-                                        float maxWidth, float[] measuredWidth);
+                                        float maxWidth, int bidiFlags, float[] measuredWidth);
 
     /**
      * Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1423,12 +1521,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(text, measureForwards, maxWidth, measuredWidth);
+            return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling,
+        int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
                 measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
@@ -1436,7 +1534,7 @@
     }
 
     private native int native_breakText(String text, boolean measureForwards,
-                                        float maxWidth, float[] measuredWidth);
+                                        float maxWidth, int bidiFlags, float[] measuredWidth);
 
     /**
      * Return the advance widths for the characters in the string.
@@ -1462,12 +1560,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_getTextWidths(mNativePaint, text, index, count, widths);
+            return native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_getTextWidths(mNativePaint, text, index, count, widths);
+        int res = native_getTextWidths(mNativePaint, text, index, count, mBidiFlags, widths);
         setTextSize(oldSize);
         for (int i=0; i<res; i++) {
             widths[i] *= mInvCompatScaling;
@@ -1544,12 +1642,12 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_getTextWidths(mNativePaint, text, start, end, widths);
+            return native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_getTextWidths(mNativePaint, text, start, end, widths);
+        int res = native_getTextWidths(mNativePaint, text, start, end, mBidiFlags, widths);
         setTextSize(oldSize);
         for (int i=0; i<res; i++) {
             widths[i] *= mInvCompatScaling;
@@ -1570,19 +1668,62 @@
     }
 
     /**
+     * Return the glyph Ids for the characters in the string.
+     *
+     * @param text   The text to measure
+     * @param start  The index of the first char to to measure
+     * @param end    The end of the text slice to measure
+     * @param contextStart the index of the first character to use for shaping context,
+     * must be <= start
+     * @param contextEnd the index past the last character to use for shaping context,
+     * must be >= end
+     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+     * or {@link #DIRECTION_RTL}
+     * @param glyphs array to receive the glyph Ids of the characters.
+     *               Must be at least a large as the text.
+     * @return       the number of glyphs in the returned array
+     *
+     * @hide
+     *
+     * Used only for BiDi / RTL Tests
+     */
+    public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
+            int flags, char[] glyphs) {
+        if (text == null) {
+            throw new IllegalArgumentException("text cannot be null");
+        }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
+        if ((start | end | contextStart | contextEnd | (end - start)
+                | (start - contextStart) | (contextEnd - end) | (text.length() - end)
+                | (text.length() - contextEnd)) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (end - start > glyphs.length) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        return native_getTextGlyphs(mNativePaint, text, start, end, contextStart, contextEnd,
+                flags, glyphs);
+    }
+
+    /**
      * Convenience overload that takes a char array instead of a
      * String.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, float[], int)
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
      * @hide
      */
     public float getTextRunAdvances(char[] chars, int index, int count,
-            int contextIndex, int contextCount, float[] advances,
+            int contextIndex, int contextCount, int flags, float[] advances,
             int advancesIndex) {
 
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
         if ((index | count | contextIndex | contextCount | advancesIndex
                 | (index - contextIndex) | (contextCount - count)
                 | ((contextIndex + contextCount) - (index + count))
@@ -1597,13 +1738,13 @@
         }
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, chars, index, count,
-                    contextIndex, contextCount, advances, advancesIndex);
+                    contextIndex, contextCount, flags, advances, advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
-                contextIndex, contextCount, advances, advancesIndex);
+                contextIndex, contextCount, flags, advances, advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1618,11 +1759,11 @@
      * Convenience overload that takes a CharSequence instead of a
      * String.
      *
-     * @see #getTextRunAdvances(String, int, int, int, int, float[], int)
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
      * @hide
      */
     public float getTextRunAdvances(CharSequence text, int start, int end,
-            int contextStart, int contextEnd, float[] advances,
+            int contextStart, int contextEnd, int flags, float[] advances,
             int advancesIndex) {
 
         if (text == null) {
@@ -1638,16 +1779,16 @@
 
         if (text instanceof String) {
             return getTextRunAdvances((String) text, start, end,
-                    contextStart, contextEnd, advances, advancesIndex);
+                    contextStart, contextEnd, flags, advances, advancesIndex);
         }
         if (text instanceof SpannedString ||
             text instanceof SpannableString) {
             return getTextRunAdvances(text.toString(), start, end,
-                    contextStart, contextEnd, advances, advancesIndex);
+                    contextStart, contextEnd, flags, advances, advancesIndex);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunAdvances(start, end,
-                    contextStart, contextEnd, advances, advancesIndex, this);
+                    contextStart, contextEnd, flags, advances, advancesIndex, this);
         }
         if (text.length() == 0 || end == start) {
             return 0f;
@@ -1658,7 +1799,7 @@
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
         float result = getTextRunAdvances(buf, start - contextStart, len,
-                0, contextLen, advances, advancesIndex);
+                0, contextLen, flags, advances, advancesIndex);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -1695,6 +1836,8 @@
      * must be <= start
      * @param contextEnd the index past the last character to use for shaping context,
      * must be >= end
+     * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
+     * or {@link #DIRECTION_RTL}
      * @param advances array to receive the advances, must have room for all advances,
      * can be null if only total advance is needed
      * @param advancesIndex the position in advances at which to put the
@@ -1704,11 +1847,14 @@
      * @hide
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
-            int contextEnd, float[] advances, int advancesIndex) {
+            int contextEnd, int flags, float[] advances, int advancesIndex) {
 
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
         if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
                 | (start - contextStart) | (contextEnd - end)
                 | (text.length() - contextEnd)
@@ -1723,13 +1869,13 @@
 
         if (!mHasCompatScaling) {
             return native_getTextRunAdvances(mNativePaint, text, start, end,
-                    contextStart, contextEnd, advances, advancesIndex);
+                    contextStart, contextEnd, flags, advances, advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
         float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
-                contextStart, contextEnd, advances, advancesIndex);
+                contextStart, contextEnd, flags, advances, advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -1758,6 +1904,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextLength the length of the context
+     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1766,7 +1913,7 @@
      * @hide
      */
     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
-            int offset, int cursorOpt) {
+            int flags, int offset, int cursorOpt) {
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -1776,7 +1923,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextLength, offset, cursorOpt);
+                contextStart, contextLength, flags, offset, cursorOpt);
     }
 
     /**
@@ -1797,6 +1944,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
+     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1805,22 +1953,22 @@
      * @hide
      */
     public int getTextRunCursor(CharSequence text, int contextStart,
-           int contextEnd, int offset, int cursorOpt) {
+           int contextEnd, int flags, int offset, int cursorOpt) {
 
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             return getTextRunCursor(text.toString(), contextStart, contextEnd,
-                    offset, cursorOpt);
+                    flags, offset, cursorOpt);
         }
         if (text instanceof GraphicsOperations) {
             return ((GraphicsOperations) text).getTextRunCursor(
-                    contextStart, contextEnd, offset, cursorOpt, this);
+                    contextStart, contextEnd, flags, offset, cursorOpt, this);
         }
 
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int result = getTextRunCursor(buf, 0, contextLen, offset - contextStart, cursorOpt);
+        int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
         return result;
     }
@@ -1843,6 +1991,7 @@
      * @param text the text
      * @param contextStart the start of the context
      * @param contextEnd the end of the context
+     * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
      * @param offset the cursor position to move from
      * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
      * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -1851,7 +2000,7 @@
      * @hide
      */
     public int getTextRunCursor(String text, int contextStart, int contextEnd,
-            int offset, int cursorOpt) {
+            int flags, int offset, int cursorOpt) {
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
                 | (text.length() - contextEnd) | cursorOpt) < 0)
@@ -1860,7 +2009,7 @@
         }
 
         return native_getTextRunCursor(mNativePaint, text,
-                contextStart, contextEnd, offset, cursorOpt);
+                contextStart, contextEnd, flags, offset, cursorOpt);
     }
 
     /**
@@ -1881,7 +2030,7 @@
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, text, index, count, x, y,
+        native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, 
                 path.ni());
     }
 
@@ -1903,7 +2052,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, text, start, end, x, y,
+        native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, 
                 path.ni());
     }
     
@@ -1924,7 +2073,7 @@
         if (bounds == null) {
             throw new NullPointerException("need bounds Rect");
         }
-        nativeGetStringBounds(mNativePaint, text, start, end, bounds);
+        nativeGetStringBounds(mNativePaint, text, start, end, mBidiFlags, bounds);
     }
     
     /**
@@ -1944,7 +2093,7 @@
         if (bounds == null) {
             throw new NullPointerException("need bounds Rect");
         }
-        nativeGetCharArrayBounds(mNativePaint, text, index, count, bounds);
+        nativeGetCharArrayBounds(mNativePaint, text, index, count, mBidiFlags, bounds);
     }
     
     @Override
@@ -1991,29 +2140,33 @@
                                                     String locale);
 
     private static native int native_getTextWidths(int native_object,
-                            char[] text, int index, int count, float[] widths);
+                            char[] text, int index, int count, int bidiFlags, float[] widths);
     private static native int native_getTextWidths(int native_object,
-                            String text, int start, int end, float[] widths);
+                            String text, int start, int end, int bidiFlags, float[] widths);
+
+    private static native int native_getTextGlyphs(int native_object,
+            String text, int start, int end, int contextStart, int contextEnd,
+            int flags, char[] glyphs);
 
     private static native float native_getTextRunAdvances(int native_object,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            float[] advances, int advancesIndex);
+            int flags, float[] advances, int advancesIndex);
     private static native float native_getTextRunAdvances(int native_object,
             String text, int start, int end, int contextStart, int contextEnd,
-            float[] advances, int advancesIndex);
+            int flags, float[] advances, int advancesIndex);
 
     private native int native_getTextRunCursor(int native_object, char[] text,
-            int contextStart, int contextLength, int offset, int cursorOpt);
+            int contextStart, int contextLength, int flags, int offset, int cursorOpt);
     private native int native_getTextRunCursor(int native_object, String text,
-            int contextStart, int contextEnd, int offset, int cursorOpt);
+            int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
 
-    private static native void native_getTextPath(int native_object, char[] text,
-            int index, int count, float x, float y, int path);
-    private static native void native_getTextPath(int native_object, String text,
-            int start, int end, float x, float y, int path);
+    private static native void native_getTextPath(int native_object, int bidiFlags,
+                char[] text, int index, int count, float x, float y, int path);
+    private static native void native_getTextPath(int native_object, int bidiFlags,
+                String text, int start, int end, float x, float y, int path);
     private static native void nativeGetStringBounds(int nativePaint,
-                                String text, int start, int end, Rect bounds);
+                                String text, int start, int end, int bidiFlags, Rect bounds);
     private static native void nativeGetCharArrayBounds(int nativePaint,
-                                char[] text, int index, int count, Rect bounds);
+                                char[] text, int index, int count, int bidiFlags, Rect bounds);
     private static native void finalizer(int nativePaint);
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 37f2250..c90f400 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -146,6 +146,10 @@
 
         if (oldBounds.left != left || oldBounds.top != top ||
                 oldBounds.right != right || oldBounds.bottom != bottom) {
+            if (!oldBounds.isEmpty()) {
+                // first invalidate the previous bounds
+                invalidateSelf();
+            }
             mBounds.set(left, top, right, bottom);
             onBoundsChange(mBounds);
         }
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index b8564b6..5751331 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -274,12 +274,20 @@
             }
         }
 
+        // 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() {
@@ -492,7 +500,9 @@
      */
     public void copyFromUnchecked(int[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
@@ -507,7 +517,9 @@
      */
     public void copyFromUnchecked(short[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
@@ -522,7 +534,9 @@
      */
     public void copyFromUnchecked(byte[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
@@ -537,7 +551,9 @@
      */
     public void copyFromUnchecked(float[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFromUnchecked(0, mCurrentCount, d);
@@ -553,7 +569,9 @@
      */
     public void copyFrom(int[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
@@ -569,7 +587,9 @@
      */
     public void copyFrom(short[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
@@ -585,7 +605,9 @@
      */
     public void copyFrom(byte[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
@@ -601,7 +623,9 @@
      */
     public void copyFrom(float[] d) {
         mRS.validate();
-        if (mCurrentDimY > 0) {
+        if (mCurrentDimZ > 0) {
+            copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d);
+        } else if (mCurrentDimY > 0) {
             copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d);
         } else {
             copy1DRangeFrom(0, mCurrentCount, d);
@@ -967,12 +991,144 @@
             Canvas c = new Canvas(newBitmap);
             c.drawBitmap(data, 0, 0, null);
             copy2DRangeFrom(xoff, yoff, newBitmap);
+            return;
         }
         validateBitmapFormat(data);
         validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
     }
 
+    private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) {
+        if (mAdaptedAllocation != null) {
+
+        } else {
+
+            if (xoff < 0 || yoff < 0 || zoff < 0) {
+                throw new RSIllegalArgumentException("Offset cannot be negative.");
+            }
+            if (h < 0 || w < 0 || d < 0) {
+                throw new RSIllegalArgumentException("Height or width cannot be negative.");
+            }
+            if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
+                throw new RSIllegalArgumentException("Updated region larger than allocation.");
+            }
+        }
+    }
+
+    /**
+     * @hide
+     *
+     */
+    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, byte[] data) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                              w, h, d, data, data.length);
+    }
+
+    /**
+     * @hide
+     *
+     */
+    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, short[] data) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                              w, h, d, data, data.length * 2);
+    }
+
+    /**
+     * @hide
+     *
+     */
+    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, int[] data) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                              w, h, d, data, data.length * 4);
+    }
+
+    /**
+     * @hide
+     *
+     */
+    void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, float[] data) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                              w, h, d, data, data.length * 4);
+    }
+
+
+    /**
+     * @hide
+     * Copy a rectangular region from the array into the allocation.
+     * The incoming array is assumed to be tightly packed.
+     *
+     * @param xoff X offset of the region to update
+     * @param yoff Y offset of the region to update
+     * @param zoff Z offset of the region to update
+     * @param w Width of the incoming region to update
+     * @param h Height of the incoming region to update
+     * @param d Depth of the incoming region to update
+     * @param data to be placed into the allocation
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, byte[] data) {
+        validateIsInt8();
+        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
+    }
+
+    /**
+     * @hide
+     *
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, short[] data) {
+        validateIsInt16();
+        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
+    }
+
+    /**
+     * @hide
+     *
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, int[] data) {
+        validateIsInt32();
+        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
+    }
+
+    /**
+     * @hide
+     *
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, float[] data) {
+        validateIsFloat32();
+        copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data);
+    }
+
+    /**
+     * @hide
+     * Copy a rectangular region into the allocation from another
+     * allocation.
+     *
+     * @param xoff X offset of the region to update.
+     * @param yoff Y offset of the region to update.
+     * @param w Width of the incoming region to update.
+     * @param h Height of the incoming region to update.
+     * @param d Depth of the incoming region to update.
+     * @param data source allocation.
+     * @param dataXoff X offset in data of the region to update.
+     * @param dataYoff Y offset in data of the region to update.
+     * @param dataZoff Z offset in data of the region to update
+     */
+    public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d,
+                                Allocation data, int dataXoff, int dataYoff, int dataZoff) {
+        mRS.validate();
+        validate3DRange(xoff, yoff, zoff, w, h, d);
+        mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
+                              w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff,
+                              data.mSelectedLOD);
+    }
+
 
     /**
      * Copy from the Allocation into a Bitmap.  The bitmap must
@@ -1050,6 +1206,10 @@
      * A new type will be created with the new dimension.
      *
      * @param dimX The new size of the allocation.
+     *
+     * @deprecated Renderscript objects should be immutable once
+     * created.  The replacement is to create a new allocation and copy the
+     * contents.
      */
     public synchronized void resize(int dimX) {
         if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
@@ -1064,38 +1224,6 @@
         updateCacheInfo(mType);
     }
 
-    /**
-     * Resize a 2D allocation.  The contents of the allocation are
-     * preserved.  If new elements are allocated objects are created
-     * with null contents and the new region is otherwise undefined.
-     *
-     * If the new region is smaller the references of any objects
-     * outside the new region will be released.
-     *
-     * A new type will be created with the new dimension.
-     *
-     * @param dimX The new size of the allocation.
-     * @param dimY The new size of the allocation.
-     */
-    public synchronized void resize(int dimX, int dimY) {
-        if ((mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
-            throw new RSInvalidStateException(
-                "Resize only support for 2D allocations at this time.");
-        }
-        if (mType.getY() == 0) {
-            throw new RSInvalidStateException(
-                "Resize only support for 2D allocations at this time.");
-        }
-        mRS.nAllocationResize2D(getID(mRS), dimX, dimY);
-        mRS.finish();  // Necessary because resize is fifoed and update is async.
-
-        int typeID = mRS.nAllocationGetType(getID(mRS));
-        mType = new Type(typeID, mRS);
-        mType.updateFromNative();
-        updateCacheInfo(mType);
-    }
-
-
 
     // creation
 
@@ -1117,6 +1245,7 @@
         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.");
@@ -1266,7 +1395,6 @@
             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 f464f9b..c2ebc9f 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -71,6 +71,9 @@
     private int mID;
     private boolean mDestroyed;
     private String mName;
+
+    int mGCSize;
+
     RenderScript mRS;
 
     /**
@@ -135,6 +138,9 @@
             throw new RSInvalidStateException("Object already destroyed.");
         }
         mDestroyed = true;
+        if (mGCSize != 0) {
+            mRS.removeAllocSizeForGC(mGCSize);
+        }
         mRS.nObjDestroy(mID);
     }
 
diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java
index 42b508b..8b0222a 100644
--- a/graphics/java/android/renderscript/FileA3D.java
+++ b/graphics/java/android/renderscript/FileA3D.java
@@ -28,6 +28,7 @@
 import android.util.TypedValue;
 
 /**
+ * @hide
  * @deprecated in API 16
  * FileA3D allows users to load Renderscript objects from files
  * or resources stored on disk. It could be used to load items
diff --git a/graphics/java/android/renderscript/Font.java b/graphics/java/android/renderscript/Font.java
index 8a49abb..1a8d5bf 100644
--- a/graphics/java/android/renderscript/Font.java
+++ b/graphics/java/android/renderscript/Font.java
@@ -30,8 +30,9 @@
 import android.util.TypedValue;
 
 /**
+ * @hide
  * @deprecated in API 16
- * <p>This class gives users a simple way to draw hardware accelerated text. 
+ * <p>This class gives users a simple way to draw hardware accelerated text.
  * Internally, the glyphs are rendered using the Freetype library and an internal cache of
  * rendered glyph bitmaps is maintained. Each font object represents a combination of a typeface,
  * and point size. You can create multiple font objects to represent styles such as bold or italic text,
@@ -43,7 +44,7 @@
  * render large batches of text in sequence. It is also more efficient to render multiple
  * characters at once instead of one by one to improve draw call batching.</p>
  * <p>Font color and transparency are not part of the font object and you can freely modify
- * them in the script to suit the user's rendering needs. Font colors work as a state machine. 
+ * them in the script to suit the user's rendering needs. Font colors work as a state machine.
  * Every new call to draw text uses the last color set in the script.</p>
  **/
 public class Font extends BaseObj {
diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java
index 7210513..d0d383d 100644
--- a/graphics/java/android/renderscript/Mesh.java
+++ b/graphics/java/android/renderscript/Mesh.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 
 /**
+ * @hide
  * @deprecated in API 16
  * <p>This class is a container for geometric data displayed with
  * Renderscript. Internally, a mesh is a collection of allocations that
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index d9f64c6..9bd103e 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -26,6 +26,7 @@
 
 
 /**
+ * @hide
  *
  * Program is a base class for all the objects that modify
  * various stages of the graphics pipeline
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 69968ac..dd0f9f5 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -21,6 +21,7 @@
 
 
 /**
+ * @hide
  * @deprecated in API 16
  * <p>The Renderscript fragment program, also known as fragment shader is responsible
  * for manipulating pixel data in a user defined way. It's constructed from a GLSL
diff --git a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
index 848c5a3..8ae1777 100644
--- a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -21,6 +21,7 @@
 
 
 /**
+ * @hide
  * @deprecated in API 16
  * <p>ProgramFragmentFixedFunction is a helper class that provides
  * a way to make a simple fragment shader without writing any
diff --git a/graphics/java/android/renderscript/ProgramRaster.java b/graphics/java/android/renderscript/ProgramRaster.java
index c44521b..216cb4e 100644
--- a/graphics/java/android/renderscript/ProgramRaster.java
+++ b/graphics/java/android/renderscript/ProgramRaster.java
@@ -21,6 +21,7 @@
 
 
 /**
+ * @hide
  * @deprecated in API 16
  * Program raster is primarily used to specify whether point sprites are enabled and to control
  * the culling mode. By default, back faces are culled.
diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java
index d0fd6e5..dac9e76 100644
--- a/graphics/java/android/renderscript/ProgramStore.java
+++ b/graphics/java/android/renderscript/ProgramStore.java
@@ -21,6 +21,7 @@
 
 
 /**
+ * @hide
  * <p>ProgramStore contains a set of parameters that control how
  * the graphics hardware handles writes to the framebuffer.
  * It could be used to:</p>
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 2bd5124..50e32f6 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
- /**
+/**
+ * @hide
  * <p>The Renderscript vertex program, also known as a vertex shader, describes a stage in
  * the graphics pipeline responsible for manipulating geometric data in a user-defined way.
  * The object is constructed by providing the Renderscript system with the following data:</p>
@@ -43,6 +44,7 @@
 
 
 /**
+ * @hide
  * @deprecated in API 16
  * ProgramVertex, also know as a vertex shader, describes a
  * stage in the graphics pipeline responsible for manipulating
@@ -76,14 +78,15 @@
     }
 
     /**
-    * @deprecated in API 16
-    * Builder class for creating ProgramVertex objects.
-    * The builder starts empty and the user must minimally provide
-    * the GLSL shader code, and the varying inputs. Constant, or
-    * uniform parameters to the shader may optionally be provided as
-    * well.
-    *
-    **/
+     * @hide
+     * @deprecated in API 16
+     * Builder class for creating ProgramVertex objects.
+     * The builder starts empty and the user must minimally provide
+     * the GLSL shader code, and the varying inputs. Constant, or
+     * uniform parameters to the shader may optionally be provided as
+     * well.
+     *
+     **/
     public static class Builder extends BaseProgramBuilder {
         /**
          * @deprecated in API 16
diff --git a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
index 88cade4..ad486f3 100644
--- a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -22,6 +22,7 @@
 
 
 /**
+ * @hide
  * @deprecated in API 16
  * ProgramVertexFixedFunction is a helper class that provides a
  * simple way to create a fixed function emulation vertex shader
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
index 82ed95c..3c6c720 100644
--- a/graphics/java/android/renderscript/RSSurfaceView.java
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -30,6 +30,7 @@
 import android.view.SurfaceView;
 
 /**
+ * @hide
  * @deprecated in API 16
  * The Surface View for a graphics renderscript (RenderScriptGL) to draw on.
  *
diff --git a/graphics/java/android/renderscript/RSTextureView.java b/graphics/java/android/renderscript/RSTextureView.java
index ed04000..7eeeeae 100644
--- a/graphics/java/android/renderscript/RSTextureView.java
+++ b/graphics/java/android/renderscript/RSTextureView.java
@@ -29,6 +29,7 @@
 import android.view.TextureView;
 
 /**
+ * @hide
  * @deprecated in API 16
  * The Texture View for a graphics renderscript (RenderScriptGL)
  * to draw on.
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index bef28aa..d5af276 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -83,11 +83,7 @@
     native void nContextInitToClient(int con);
     native void nContextDeinitToClient(int con);
 
-    /**
-     * Name of the file that holds the object cache.
-     */
-    private static final String CACHE_PATH = "com.android.renderscript.cache";
-    static String mCachePath;
+    static File mCacheDir;
 
      /**
      * Sets the directory to use as a persistent storage for the
@@ -97,9 +93,8 @@
      * @param cacheDir A directory the current process can write to
      */
     public static void setupDiskCache(File cacheDir) {
-        File f = new File(cacheDir, CACHE_PATH);
-        mCachePath = f.getAbsolutePath();
-        f.mkdirs();
+        // Defer creation of cache path to nScriptCCreate().
+        mCacheDir = cacheDir;
     }
 
     public enum ContextType {
@@ -420,6 +415,46 @@
         rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b);
     }
 
+    native void rsnAllocationData3D(int con,
+                                    int dstAlloc, int dstXoff, int dstYoff, int dstZoff,
+                                    int dstMip,
+                                    int width, int height, int depth,
+                                    int srcAlloc, int srcXoff, int srcYoff, int srcZoff,
+                                    int srcMip);
+    synchronized void nAllocationData3D(int dstAlloc, int dstXoff, int dstYoff, int dstZoff,
+                                        int dstMip,
+                                        int width, int height, int depth,
+                                        int srcAlloc, int srcXoff, int srcYoff, int srcZoff,
+                                        int srcMip) {
+        validate();
+        rsnAllocationData3D(mContext,
+                            dstAlloc, dstXoff, dstYoff, dstZoff,
+                            dstMip, width, height, depth,
+                            srcAlloc, srcXoff, srcYoff, srcZoff, srcMip);
+    }
+
+    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, byte[] d, int sizeBytes);
+    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, byte[] d, int sizeBytes) {
+        validate();
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
+    }
+    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, short[] d, int sizeBytes);
+    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, short[] d, int sizeBytes) {
+        validate();
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
+    }
+    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, int[] d, int sizeBytes);
+    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, int[] d, int sizeBytes) {
+        validate();
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
+    }
+    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, float[] d, int sizeBytes);
+    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, float[] d, int sizeBytes) {
+        validate();
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
+    }
+
+
     native void rsnAllocationRead(int con, int id, byte[] d);
     synchronized void nAllocationRead(int id, byte[] d) {
         validate();
@@ -451,11 +486,6 @@
         validate();
         rsnAllocationResize1D(mContext, id, dimX);
     }
-    native void rsnAllocationResize2D(int con, int id, int dimX, int dimY);
-    synchronized void nAllocationResize2D(int id, int dimX, int dimY) {
-        validate();
-        rsnAllocationResize2D(mContext, id, dimX, dimY);
-    }
 
     native int  rsnFileA3DCreateFromAssetStream(int con, int assetStream);
     synchronized int nFileA3DCreateFromAssetStream(int assetStream) {
@@ -724,6 +754,8 @@
     int     mContext;
     @SuppressWarnings({"FieldCanBeLocal"})
     MessageThread mMessageThread;
+    GCThread mGCThread;
+
 
     Element mElement_U8;
     Element mElement_I8;
@@ -1006,6 +1038,49 @@
         }
     }
 
+    static class GCThread extends Thread {
+        RenderScript mRS;
+        boolean mRun = true;
+
+        int currentSize = 0;
+        final static int targetSize = 256*1024*1024; // call System.gc after 256MB of allocs
+
+        GCThread(RenderScript rs) {
+            super("RSGCThread");
+            mRS = rs;
+
+        }
+
+        public void run() {
+            while(mRun) {
+                boolean doGC = false;
+                synchronized(this) {
+                    if (currentSize >= targetSize) {
+                        doGC = true;
+                    }
+                }
+                if (doGC == true) {
+                    System.gc();
+                }
+                try {
+                    sleep(1, 0);
+                } catch(InterruptedException e) {
+                }
+            }
+            Log.d(LOG_TAG, "GCThread exiting.");
+        }
+
+        public synchronized void addAllocSize(int bytes) {
+            currentSize += bytes;
+        }
+
+        public synchronized void removeAllocSize(int bytes) {
+            currentSize -= bytes;
+        }
+
+    }
+
+
     RenderScript(Context ctx) {
         if (ctx != null) {
             mApplicationContext = ctx.getApplicationContext();
@@ -1028,6 +1103,15 @@
         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.
      *
@@ -1044,7 +1128,9 @@
             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;
     }
 
@@ -1099,8 +1185,10 @@
         validate();
         nContextDeinitToClient(mContext);
         mMessageThread.mRun = false;
+        mGCThread.mRun = false;
         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 5269405..fad8838 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -29,6 +29,7 @@
 import android.view.SurfaceView;
 
 /**
+ * @hide
  * @deprecated in API 16
  * The Graphics derivitive of Renderscript.  Extends the basic context to add a
  * root script which is the display window for graphical output.  When the
@@ -197,6 +198,9 @@
         }
         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 108b230..2f69775 100644
--- a/graphics/java/android/renderscript/ScriptC.java
+++ b/graphics/java/android/renderscript/ScriptC.java
@@ -60,8 +60,16 @@
             throw new RSRuntimeException("Loading of ScriptC script failed.");
         }
         setID(id);
+        mGCSize = 2 * 1024 * 1024;
+        rs.addAllocSizeForGC(mGCSize);
     }
 
+    /**
+     * Name of the file that holds the object cache.
+     */
+    private static final String CACHE_PATH = "com.android.renderscript.cache";
+
+    static String mCachePath;
 
     private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID) {
         byte[] pgm;
@@ -94,7 +102,13 @@
 
         String resName = resources.getResourceEntryName(resourceID);
 
+        // Create the RS cache path if we haven't done so already.
+        if (mCachePath == null) {
+            File f = new File(rs.mCacheDir, CACHE_PATH);
+            mCachePath = f.getAbsolutePath();
+            f.mkdirs();
+        }
         Log.v(TAG, "Create script for resource = " + resName);
-        return rs.nScriptCCreate(resName, rs.mCachePath, pgm, pgmLength);
+        return rs.nScriptCCreate(resName, mCachePath, pgm, pgmLength);
     }
 }
diff --git a/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java b/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java
index 24af6ea..3e58b87 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsic3DLUT.java
@@ -45,7 +45,7 @@
         int id = rs.nScriptIntrinsicCreate(8, e.getID(rs));
 
         if (!e.isCompatible(Element.U8_4(rs))) {
-            throw new RSIllegalArgumentException("Element must be compatibile with uchar4.");
+            throw new RSIllegalArgumentException("Element must be compatible with uchar4.");
         }
 
         return new ScriptIntrinsic3DLUT(id, rs, e);
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicBlur.java b/graphics/java/android/renderscript/ScriptIntrinsicBlur.java
index 7ffd1e7..2848f64 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicBlur.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicBlur.java
@@ -46,7 +46,7 @@
      * @return ScriptIntrinsicBlur
      */
     public static ScriptIntrinsicBlur create(RenderScript rs, Element e) {
-        if ((e != Element.U8_4(rs)) && e != (Element.U8(rs))) {
+        if ((!e.isCompatible(Element.U8_4(rs))) && (!e.isCompatible(Element.U8(rs)))) {
             throw new RSIllegalArgumentException("Unsuported element type.");
         }
         int id = rs.nScriptIntrinsicCreate(5, e.getID(rs));
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
index b219978..f7e844e 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
@@ -47,7 +47,7 @@
      * @return ScriptIntrinsicColorMatrix
      */
     public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) {
-        if (e != Element.U8_4(rs)) {
+        if (!e.isCompatible(Element.U8_4(rs))) {
             throw new RSIllegalArgumentException("Unsuported element type.");
         }
         int id = rs.nScriptIntrinsicCreate(2, e.getID(rs));
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
index b40ea84..d54df96 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -48,7 +48,7 @@
      */
     public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) {
         float f[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0};
-        if (e != Element.U8_4(rs)) {
+        if (!e.isCompatible(Element.U8_4(rs))) {
             throw new RSIllegalArgumentException("Unsuported element type.");
         }
         int id = rs.nScriptIntrinsicCreate(1, e.getID(rs));
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index 9507030..d7c8255 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -110,6 +110,16 @@
     }
 
     /**
+     * Get the YUV format
+     *
+     * @hide
+     * @return int
+     */
+    public int getYuv() {
+        return mDimYuv;
+    }
+
+    /**
      * Return if the Type has a mipmap chain.
      *
      * @return boolean
diff --git a/graphics/java/android/renderscript/package.html b/graphics/java/android/renderscript/package.html
index 5eab23c..eb178c1 100644
--- a/graphics/java/android/renderscript/package.html
+++ b/graphics/java/android/renderscript/package.html
@@ -1,86 +1,10 @@
 <HTML>
 <BODY>
-<p>The Renderscript rendering and computational APIs offer a low-level, high performance means of
-carrying out mathematical calculations and 3D graphics rendering.</p>
+<p>RenderScript provides support for high-performance computation across heterogeneous processors.</p>
 
 <p>For more information, see the
-<a href="{@docRoot}guide/topics/renderscript/index.html">Renderscript</a> developer guide.</p>
+<a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
 {@more}
 
-<p>An example of Renderscript in applications include the 3D carousel view that is present in
-Android 3.0 applications such as the Books and YouTube applications. This API is intended for
-developers who are comfortable working with native code and want to maximize their performance
-critical applications.</p>
-
-<p>Renderscript adopts a control and slave architecture where the low-level native code is controlled by the
-higher level Android system that runs in the virtual machine (VM). The VM code handles resource
-allocation and lifecycle management of the Renderscript enabled application and calls the Renderscript
-code through high level entry points. The Android build tools generate these entry points through reflection on
-the native Renderscript code, which you write in C (C99 standard). The Renderscript code
-does the intensive computation and returns the result back to the Android VM.</p>
-
-<p>You can find the Renderscript native
-APIs in the <code>&lt;sdk_root&gt;/platforms/android-11/renderscript</code> directory.
-The Android system APIs are broken into a few main groups:</p>
-
-<h4>Core</h4>
-<p>These classes are used internally by the system for memory allocation. They are used by the classes that
-are generated by the build tools:</p>
-<ul>
-  <li>Allocation</li>
-  <li>Element</li>
-  <li>Type</li>
-  <li>Script</li>
-</ul>
-
-
-<h4>Data Types</h4>
-<p>These data types are used by the classes that are generated
-by the build tools. They are the reflected counterparts of the native data types that
-are defined by the native Renderscript APIs and used by your Renderscript code. The
-classes include:</p>
-<ul>
-  <li>Byte2, Byte3, and Byte4</li>
-  <li>Float2, Float3, Float4</li>
-  <li>Int2, Int3, Int4</li>
-  <li>Long2, Long3, Long4</li>
-  <li>Matrix2f, Matrix3f, Matrix4f</li>
-  <li>Short2, Short3, Short4</li>
-</ul>
-
-<p>For example, if you declared the following struct in your .rs Renderscript file:</p>
-
-<pre>struct Hello { float3 position; rs_matrix4x4 transform; }</pre>
-
-<p>The build tools generate a class through reflection that looks like the following:</p>
-<pre>
-class Hello {
-    static public class Item {
-        Float4 position;
-        Matrix4f transform;
-    }
-Element createElement(RenderScript rs) {
-        Element.Builder eb = new Element.Builder(rs);
-        eb.add(Element.F32_3(rs), "position");
-        eb.add(Element.MATRIX_4X4(rs), "transform");
-        return eb.create();
-    }
-}
-</pre>
-
-<h4>Graphics</h4>
-<p>These classes are specific to graphics Renderscripts and support a typical rendering
-pipeline.</p>
-<ul>
-<li>Mesh</li>
-<li>ProgramFragment</li>
-<li>ProgramRaster</li>
-<li>ProgramStore</li>
-<li>ProgramVertex</li>
-<li>RSSurfaceView</li>
-<li>Sampler</li>
-</ul>
-
-</p>
 </BODY>
 </HTML>
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index 80d7728..e8beae53 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -10,6 +10,7 @@
         libnativehelper \
         libRS \
         libcutils \
+        liblog \
         libskia \
         libutils \
         libui \
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 8757b19..460a516 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -725,6 +725,72 @@
 }
 
 static void
+nAllocationData3D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
+                    jint w, jint h, jint d, jshortArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation3DData_s, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
+    jshort *ptr = _env->GetShortArrayElements(data, NULL);
+    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+    _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData3D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
+                    jint w, jint h, jint d, jbyteArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation3DData_b, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
+    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData3D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
+                    jint w, jint h, jint d, jintArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation3DData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
+    jint *ptr = _env->GetIntArrayElements(data, NULL);
+    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+    _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData3D_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
+                    jint w, jint h, jint d, jfloatArray data, int sizeBytes)
+{
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation3DData_f, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
+    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
+    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+    _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationData3D_alloc(JNIEnv *_env, jobject _this, RsContext con,
+                        jint dstAlloc, jint dstXoff, jint dstYoff, jint dstZoff,
+                        jint dstMip,
+                        jint width, jint height, jint depth,
+                        jint srcAlloc, jint srcXoff, jint srcYoff, jint srcZoff,
+                        jint srcMip)
+{
+    LOG_API("nAllocationData3D_alloc, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
+            " dstMip(%i), width(%i), height(%i),"
+            " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i)",
+            con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
+            width, height, (RsAllocation)srcAlloc, srcXoff, srcYoff, srcMip, srcFace);
+
+    rsAllocationCopy3DRange(con,
+                            (RsAllocation)dstAlloc,
+                            dstXoff, dstYoff, dstZoff, dstMip,
+                            width, height, depth,
+                            (RsAllocation)srcAlloc,
+                            srcXoff, srcYoff, srcZoff, srcMip);
+}
+
+static void
 nAllocationRead_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jintArray data)
 {
     jint len = _env->GetArrayLength(data);
@@ -782,13 +848,6 @@
     rsAllocationResize1D(con, (RsAllocation)alloc, dimX);
 }
 
-static void
-nAllocationResize2D(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint dimX, jint dimY)
-{
-    LOG_API("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i), sizeY(%i)", con, (RsAllocation)alloc, dimX, dimY);
-    rsAllocationResize2D(con, (RsAllocation)alloc, dimX, dimY);
-}
-
 // -----------------------------------
 
 static int
@@ -1519,13 +1578,17 @@
 {"rsnAllocationData2D",              "(IIIIIIII[BI)V",                        (void*)nAllocationData2D_b },
 {"rsnAllocationData2D",              "(IIIIIIII[FI)V",                        (void*)nAllocationData2D_f },
 {"rsnAllocationData2D",              "(IIIIIIIIIIIII)V",                      (void*)nAllocationData2D_alloc },
+{"rsnAllocationData3D",              "(IIIIIIIII[II)V",                       (void*)nAllocationData3D_i },
+{"rsnAllocationData3D",              "(IIIIIIIII[SI)V",                       (void*)nAllocationData3D_s },
+{"rsnAllocationData3D",              "(IIIIIIIII[BI)V",                       (void*)nAllocationData3D_b },
+{"rsnAllocationData3D",              "(IIIIIIIII[FI)V",                       (void*)nAllocationData3D_f },
+{"rsnAllocationData3D",              "(IIIIIIIIIIIIII)V",                     (void*)nAllocationData3D_alloc },
 {"rsnAllocationRead",                "(II[I)V",                               (void*)nAllocationRead_i },
 {"rsnAllocationRead",                "(II[S)V",                               (void*)nAllocationRead_s },
 {"rsnAllocationRead",                "(II[B)V",                               (void*)nAllocationRead_b },
 {"rsnAllocationRead",                "(II[F)V",                               (void*)nAllocationRead_f },
 {"rsnAllocationGetType",             "(II)I",                                 (void*)nAllocationGetType},
 {"rsnAllocationResize1D",            "(III)V",                                (void*)nAllocationResize1D },
-{"rsnAllocationResize2D",            "(IIII)V",                               (void*)nAllocationResize2D },
 {"rsnAllocationGenerateMipmaps",     "(II)V",                                 (void*)nAllocationGenerateMipmaps },
 
 {"rsnScriptBindAllocation",          "(IIII)V",                               (void*)nScriptBindAllocation },
diff --git a/include/androidfw/InputDevice.h b/include/androidfw/InputDevice.h
index 1aecf80..45dc2db 100644
--- a/include/androidfw/InputDevice.h
+++ b/include/androidfw/InputDevice.h
@@ -64,6 +64,7 @@
         float max;
         float flat;
         float fuzz;
+        float resolution;
     };
 
     void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier,
@@ -83,7 +84,7 @@
 
     void addSource(uint32_t source);
     void addMotionRange(int32_t axis, uint32_t source,
-            float min, float max, float flat, float fuzz);
+            float min, float max, float flat, float fuzz, float resolution);
     void addMotionRange(const MotionRange& range);
 
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
index 5706bce..8712995 100644
--- a/include/androidfw/InputTransport.h
+++ b/include/androidfw/InputTransport.h
@@ -168,6 +168,9 @@
      */
     status_t receiveMessage(InputMessage* msg);
 
+    /* Returns a new object that has a duplicate of this channel's fd. */
+    sp<InputChannel> dup() const;
+
 private:
     String8 mName;
     int mFd;
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
index 79a7630..18225a5 100644
--- a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
@@ -28,11 +28,27 @@
 import javax.security.auth.x500.X500Principal;
 
 /**
- * This provides the required parameters needed for initializing the KeyPair
- * generator that works with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
- * facility</a>.
- * @hide
+ * This provides the required parameters needed for initializing the
+ * {@code KeyPairGenerator} that works with <a href="{@docRoot}
+ * guide/topics/security/keystore.html">Android KeyStore facility</a>. The
+ * Android KeyStore facility is accessed through a
+ * {@link java.security.KeyPairGenerator} API using the
+ * {@code AndroidKeyPairGenerator} provider. The {@code context} passed in may
+ * be used to pop up some UI to ask the user to unlock or initialize the Android
+ * keystore facility.
+ * <p>
+ * After generation, the {@code keyStoreAlias} is used with the
+ * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
+ * interface to retrieve the {@link PrivateKey} and its associated
+ * {@link Certificate} chain.
+ * <p>
+ * The KeyPair generator will create a self-signed certificate with the subject
+ * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer
+ * Distinguished Name along with the other parameters specified with the
+ * {@link Builder}.
+ * <p>
+ * The self-signed certificate may be replaced at a later time by a certificate
+ * signed by a real Certificate Authority.
  */
 public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
     private final String mKeystoreAlias;
@@ -74,6 +90,7 @@
      *            period
      * @throws IllegalArgumentException when any argument is {@code null} or
      *             {@code endDate} is before {@code startDate}.
+     * @hide should be built with AndroidKeyPairGeneratorSpecBuilder
      */
     public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
             X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
@@ -142,4 +159,121 @@
     Date getEndDate() {
         return mEndDate;
     }
+
+    /**
+     * Builder class for {@link AndroidKeyPairGeneratorSpec} objects.
+     * <p>
+     * This will build a parameter spec for use with the <a href="{@docRoot}
+     * guide/topics/security/keystore.html">Android KeyStore facility</a>.
+     * <p>
+     * The required fields must be filled in with the builder.
+     * <p>
+     * Example:
+     *
+     * <pre class="prettyprint">
+     * Calendar start = new Calendar();
+     * Calendar end = new Calendar();
+     * end.add(1, Calendar.YEAR);
+     *
+     * AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(mContext)
+     *         .setAlias("myKey")
+     *         .setSubject(new X500Principal("CN=myKey"))
+     *         .setSerial(BigInteger.valueOf(1337))
+     *         .setStartDate(start.getTime())
+     *         .setEndDate(end.getTime())
+     *         .build();
+     * </pre>
+     */
+    public static class Builder {
+        private final Context mContext;
+
+        private String mKeystoreAlias;
+
+        private X500Principal mSubjectDN;
+
+        private BigInteger mSerialNumber;
+
+        private Date mStartDate;
+
+        private Date mEndDate;
+
+        public Builder(Context context) {
+            if (context == null) {
+                throw new NullPointerException("context == null");
+            }
+            mContext = context;
+        }
+
+        /**
+         * Sets the alias to be used to retrieve the key later from a
+         * {@link java.security.KeyStore} instance using the
+         * {@code AndroidKeyStore} provider.
+         */
+        public Builder setAlias(String alias) {
+            if (alias == null) {
+                throw new NullPointerException("alias == null");
+            }
+            mKeystoreAlias = alias;
+            return this;
+        }
+
+        /**
+         * Sets the subject used for the self-signed certificate of the
+         * generated key pair.
+         */
+        public Builder setSubject(X500Principal subject) {
+            if (subject == null) {
+                throw new NullPointerException("subject == null");
+            }
+            mSubjectDN = subject;
+            return this;
+        }
+
+        /**
+         * Sets the serial number used for the self-signed certificate of the
+         * generated key pair.
+         */
+        public Builder setSerialNumber(BigInteger serialNumber) {
+            if (serialNumber == null) {
+                throw new NullPointerException("serialNumber == null");
+            }
+            mSerialNumber = serialNumber;
+            return this;
+        }
+
+        /**
+         * Sets the start of the validity period for the self-signed certificate
+         * of the generated key pair.
+         */
+        public Builder setStartDate(Date startDate) {
+            if (startDate == null) {
+                throw new NullPointerException("startDate == null");
+            }
+            mStartDate = startDate;
+            return this;
+        }
+
+        /**
+         * Sets the end of the validity period for the self-signed certificate
+         * of the generated key pair.
+         */
+        public Builder setEndDate(Date endDate) {
+            if (endDate == null) {
+                throw new NullPointerException("endDate == null");
+            }
+            mEndDate = endDate;
+            return this;
+        }
+
+        /**
+         * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
+         *
+         * @throws IllegalArgumentException if a required field is missing
+         * @return built instance of {@code AndroidKeyPairGeneratorSpec}
+         */
+        public AndroidKeyPairGeneratorSpec build() {
+            return new AndroidKeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
+                    mSerialNumber, mStartDate, mEndDate);
+        }
+    }
 }
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 65d7b8f..8a9826b 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -453,17 +453,19 @@
          * convention.
          */
         final String[] certAliases = mKeyStore.saw(Credentials.USER_CERTIFICATE);
-        for (String alias : certAliases) {
-            final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
-            if (certBytes == null) {
-                continue;
-            }
+        if (certAliases != null) {
+            for (String alias : certAliases) {
+                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+                if (certBytes == null) {
+                    continue;
+                }
 
-            final Certificate c = toCertificate(certBytes);
-            nonCaEntries.add(alias);
+                final Certificate c = toCertificate(certBytes);
+                nonCaEntries.add(alias);
 
-            if (cert.equals(c)) {
-                return alias;
+                if (cert.equals(c)) {
+                    return alias;
+                }
             }
         }
 
@@ -472,19 +474,22 @@
          * PrivateKeyEntry we looked at above.
          */
         final String[] caAliases = mKeyStore.saw(Credentials.CA_CERTIFICATE);
-        for (String alias : caAliases) {
-            if (nonCaEntries.contains(alias)) {
-                continue;
-            }
+        if (certAliases != null) {
+            for (String alias : caAliases) {
+                if (nonCaEntries.contains(alias)) {
+                    continue;
+                }
 
-            final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
-            if (certBytes == null) {
-                continue;
-            }
+                final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+                if (certBytes == null) {
+                    continue;
+                }
 
-            final Certificate c = toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
-            if (cert.equals(c)) {
-                return alias;
+                final Certificate c =
+                        toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
+                if (cert.equals(c)) {
+                    return alias;
+                }
             }
         }
 
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index d8109ce..166849d 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -49,6 +49,8 @@
 
     public static final String INSTALL_ACTION = "android.credentials.INSTALL";
 
+    public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
+
     public static final String UNLOCK_ACTION = "com.android.credentials.UNLOCK";
 
     /** Key prefix for CA certificates. */
@@ -83,6 +85,12 @@
     public static final String EXTENSION_PFX = ".pfx";
 
     /**
+     * Intent extra: install the certificate bundle as this UID instead of
+     * system.
+     */
+    public static final String EXTRA_INSTALL_AS_UID = "install_as_uid";
+
+    /**
      * Intent extra: name for the user's private key.
      */
     public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name";
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index d7119fff..c99dff0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -356,6 +356,30 @@
         }
     }
 
+    /**
+     * Returns {@code true} if the current device's {@code KeyChain} supports a
+     * specific {@code PrivateKey} type indicated by {@code algorithm} (e.g.,
+     * "RSA").
+     */
+    public static boolean isKeyAlgorithmSupported(String algorithm) {
+        return "RSA".equals(algorithm);
+    }
+
+    /**
+     * Returns {@code true} if the current device's {@code KeyChain} binds any
+     * {@code PrivateKey} of the given {@code algorithm} to the device once
+     * imported or generated. This can be used to tell if there is special
+     * hardware support that can be used to bind keys to the device in a way
+     * that makes it non-exportable.
+     */
+    public static boolean isBoundKeyAlgorithm(String algorithm) {
+        if (!isKeyAlgorithmSupported(algorithm)) {
+            return false;
+        }
+
+        return KeyStore.getInstance().isHardwareBacked();
+    }
+
     private static X509Certificate toCertificate(byte[] bytes) {
         if (bytes == null) {
             throw new IllegalArgumentException("bytes == null");
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 4b69317..852f0bb 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -87,9 +87,22 @@
         }
     }
 
-    public boolean put(String key, byte[] value) {
+    public boolean put(String key, byte[] value, int uid) {
         try {
-            return mBinder.insert(key, value, -1) == NO_ERROR;
+            return mBinder.insert(key, value, uid) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+    public boolean put(String key, byte[] value) {
+        return put(key, value, -1);
+    }
+
+    public boolean delete(String key, int uid) {
+        try {
+            return mBinder.del(key, uid) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -97,8 +110,12 @@
     }
 
     public boolean delete(String key) {
+        return delete(key, -1);
+    }
+
+    public boolean contains(String key, int uid) {
         try {
-            return mBinder.del(key, -1) == NO_ERROR;
+            return mBinder.exist(key, uid) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -106,23 +123,22 @@
     }
 
     public boolean contains(String key) {
-        try {
-            return mBinder.exist(key, -1) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
+        return contains(key, -1);
     }
 
-    public String[] saw(String prefix) {
+    public String[] saw(String prefix, int uid) {
         try {
-            return mBinder.saw(prefix, -1);
+            return mBinder.saw(prefix, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
         }
     }
 
+    public String[] saw(String prefix) {
+        return saw(prefix, -1);
+    }
+
     public boolean reset() {
         try {
             return mBinder.reset() == NO_ERROR;
@@ -169,9 +185,22 @@
         }
     }
 
-    public boolean generate(String key) {
+    public boolean generate(String key, int uid) {
         try {
-            return mBinder.generate(key, -1) == NO_ERROR;
+            return mBinder.generate(key, uid) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+    public boolean generate(String key) {
+        return generate(key, -1);
+    }
+
+    public boolean importKey(String keyName, byte[] key, int uid) {
+        try {
+            return mBinder.import_key(keyName, key, uid) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
@@ -179,12 +208,7 @@
     }
 
     public boolean importKey(String keyName, byte[] key) {
-        try {
-            return mBinder.import_key(keyName, key, -1) == NO_ERROR;
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return false;
-        }
+        return importKey(keyName, key, -1);
     }
 
     public byte[] getPubkey(String key) {
@@ -196,15 +220,19 @@
         }
     }
 
-    public boolean delKey(String key) {
+    public boolean delKey(String key, int uid) {
         try {
-            return mBinder.del_key(key, -1) == NO_ERROR;
+            return mBinder.del_key(key, uid) == NO_ERROR;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
         }
     }
 
+    public boolean delKey(String key) {
+        return delKey(key, -1);
+    }
+
     public byte[] sign(String key, byte[] data) {
         try {
             return mBinder.sign(key, data);
@@ -259,6 +287,33 @@
         }
     }
 
+    public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
+        try {
+            return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+    public boolean isHardwareBacked() {
+        try {
+            return mBinder.is_hardware_backed() == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+    public boolean clearUid(int uid) {
+        try {
+            return mBinder.clear_uid(uid) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
     public int getLastError() {
         return mError;
     }
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
index e6a3750..3d275cd 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
@@ -53,6 +53,26 @@
         assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
     }
 
+    public void testBuilder_Success() throws Exception {
+        AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(getContext())
+                .setAlias(TEST_ALIAS_1)
+                .setSubject(TEST_DN_1)
+                .setSerialNumber(SERIAL_1)
+                .setStartDate(NOW)
+                .setEndDate(NOW_PLUS_10_YEARS)
+                .build();
+
+        assertEquals("Context should be the one specified", getContext(), spec.getContext());
+
+        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
+
+        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
+
+        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
+
+        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
+    }
+
     public void testConstructor_NullContext_Failure() throws Exception {
         try {
             new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
index cd031b4..69007c4 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -67,7 +67,9 @@
         assertTrue(mAndroidKeyStore.password("1111"));
         assertTrue(mAndroidKeyStore.isUnlocked());
 
-        assertEquals(0, mAndroidKeyStore.saw("").length);
+        String[] aliases = mAndroidKeyStore.saw("");
+        assertNotNull(aliases);
+        assertEquals(0, aliases.length);
 
         mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
     }
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 07a2d7b..1de1eaf 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -17,6 +17,7 @@
 package android.security;
 
 import android.app.Activity;
+import android.os.Process;
 import android.security.KeyStore;
 import android.test.ActivityUnitTestCase;
 import android.test.AssertionFailedError;
@@ -128,7 +129,7 @@
         super.tearDown();
     }
 
-    public void teststate() throws Exception {
+    public void testState() throws Exception {
         assertEquals(KeyStore.State.UNINITIALIZED, mKeyStore.state());
     }
 
@@ -154,6 +155,24 @@
         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.contains(TEST_KEYNAME, Process.WIFI_UID));
+        mKeyStore.password(TEST_PASSWD);
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+        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.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        mKeyStore.password(TEST_PASSWD);
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+    }
+
     public void testI18n() throws Exception {
         assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
         assertFalse(mKeyStore.contains(TEST_I18N_KEY));
@@ -167,22 +186,64 @@
         mKeyStore.password(TEST_PASSWD);
         assertFalse(mKeyStore.delete(TEST_KEYNAME));
 
-        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
         assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
         assertTrue(mKeyStore.delete(TEST_KEYNAME));
         assertNull(mKeyStore.get(TEST_KEYNAME));
     }
 
+    public void testDelete_grantedUid_Wifi() throws Exception {
+        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
+        mKeyStore.password(TEST_PASSWD);
+        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
+
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+    }
+
+    public void testDelete_ungrantedUid_Bluetooth() throws Exception {
+        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        mKeyStore.password(TEST_PASSWD);
+        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+    }
+
     public void testContains() throws Exception {
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        mKeyStore.password(TEST_PASSWD);
+        assertTrue(mKeyStore.password(TEST_PASSWD));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
+        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
     }
 
+    public void testContains_grantedUid_Wifi() throws Exception {
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+
+        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.contains(TEST_KEYNAME, Process.WIFI_UID));
+    }
+
+    public void testContains_grantedUid_Bluetooth() throws Exception {
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+        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.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+    }
+
     public void testSaw() throws Exception {
         String[] emptyResult = mKeyStore.saw(TEST_KEYNAME);
         assertNotNull(emptyResult);
@@ -198,6 +259,48 @@
                      new HashSet(Arrays.asList(results)));
     }
 
+    public void testSaw_ungrantedUid_Bluetooth() throws Exception {
+        String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
+        assertNull(results1);
+
+        mKeyStore.password(TEST_PASSWD);
+        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
+        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);
+
+        String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
+        assertNull(results2);
+    }
+
+    public void testSaw_grantedUid_Wifi() throws Exception {
+        String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
+        assertNotNull(results1);
+        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);
+
+        String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
+        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
+                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
+                     new HashSet(Arrays.asList(results2)));
+    }
+
+    public void testSaw_grantedUid_Vpn() throws Exception {
+        String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
+        assertNotNull(results1);
+        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);
+
+        String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
+        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
+                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
+                     new HashSet(Arrays.asList(results2)));
+    }
+
     public void testLock() throws Exception {
         assertFalse(mKeyStore.lock());
 
@@ -239,17 +342,57 @@
     }
 
     public void testGenerate_Success() throws Exception {
-        mKeyStore.password(TEST_PASSWD);
+        assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key when unlocked",
                 mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+    }
+
+    public void testGenerate_grantedUid_Wifi_Success() throws Exception {
+        assertTrue(mKeyStore.password(TEST_PASSWD));
+
+        assertTrue("Should be able to generate key when unlocked",
+                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+    }
+
+    public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception {
+        assertTrue(mKeyStore.password(TEST_PASSWD));
+
+        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
     }
 
     public void testImport_Success() throws Exception {
-        mKeyStore.password(TEST_PASSWD);
+        assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to import key when unlocked",
                 mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+    }
+
+    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(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+    }
+
+    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.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
     }
 
     public void testImport_Failure_BadEncoding() throws Exception {
@@ -257,12 +400,15 @@
 
         assertFalse("Invalid DER-encoded key should not be imported",
                 mKeyStore.importKey(TEST_KEYNAME, TEST_DATA));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
     }
 
     public void testSign_Success() throws Exception {
         mKeyStore.password(TEST_PASSWD);
 
         assertTrue(mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
         final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
 
         assertNotNull("Signature should not be null", signature);
@@ -272,6 +418,7 @@
         mKeyStore.password(TEST_PASSWD);
 
         assertTrue(mKeyStore.generate(TEST_KEYNAME));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
         final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
 
         assertNotNull("Signature should not be null", signature);
@@ -406,6 +553,62 @@
                 mKeyStore.ungrant(TEST_KEYNAME, 0));
     }
 
+    public void testDuplicate_grantedUid_Wifi_Success() throws Exception {
+        assertTrue(mKeyStore.password(TEST_PASSWD));
+
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+
+        // source doesn't exist
+        assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, -1, TEST_KEYNAME1, Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID));
+
+        // Copy from current UID to granted UID
+        assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME1));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID));
+        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID));
+
+        // Copy from granted UID to same granted UID
+        assertTrue(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2,
+                Process.WIFI_UID));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME2, Process.WIFI_UID));
+        assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2,
+                Process.WIFI_UID));
+
+        assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME1));
+        assertTrue(mKeyStore.contains(TEST_KEYNAME2));
+        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1));
+    }
+
+    public void testDuplicate_ungrantedUid_Bluetooth_Failure() throws Exception {
+        assertTrue(mKeyStore.password(TEST_PASSWD));
+
+        assertFalse(mKeyStore.contains(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.generate(TEST_KEYNAME));
+
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, Process.BLUETOOTH_UID));
+        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, Process.BLUETOOTH_UID, TEST_KEYNAME2,
+                Process.BLUETOOTH_UID));
+
+        assertTrue(mKeyStore.contains(TEST_KEYNAME));
+        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+    }
+
     /**
      * The amount of time to allow before and after expected time for variance
      * in timing tests.
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index dcf41b7..b8d3f48 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -553,7 +553,7 @@
     if (buf == NULL) {
         ALOGE("Out of mem allocating transfer buffer");
         err = ENOMEM;
-        goto cleanup;
+        goto done;
     }
 
     // Magic fields for the ustar file format
diff --git a/libs/androidfw/InputDevice.cpp b/libs/androidfw/InputDevice.cpp
index fe891cb..f742052 100644
--- a/libs/androidfw/InputDevice.cpp
+++ b/libs/androidfw/InputDevice.cpp
@@ -172,8 +172,8 @@
 }
 
 void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
-        float flat, float fuzz) {
-    MotionRange range = { axis, source, min, max, flat, fuzz };
+        float flat, float fuzz, float resolution) {
+    MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
     mMotionRanges.add(range);
 }
 
diff --git a/libs/androidfw/InputTransport.cpp b/libs/androidfw/InputTransport.cpp
index 351c666..498389ea 100644
--- a/libs/androidfw/InputTransport.cpp
+++ b/libs/androidfw/InputTransport.cpp
@@ -219,6 +219,11 @@
     return OK;
 }
 
+sp<InputChannel> InputChannel::dup() const {
+    int fd = ::dup(getFd());
+    return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
+}
+
 
 // --- InputPublisher ---
 
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 33d8063..7b59bf2 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -5,7 +5,9 @@
 # defined in the current device/board configuration
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SRC_FILES:= \
+		utils/Blur.cpp \
 		utils/SortedListImpl.cpp \
+		thread/TaskManager.cpp \
 		font/CacheTexture.cpp \
 		font/Font.cpp \
 		FontRenderer.cpp \
@@ -32,7 +34,6 @@
 		ProgramCache.cpp \
 		RenderBufferCache.cpp \
 		ResourceCache.cpp \
-		ShapeCache.cpp \
 		SkiaColorFilter.cpp \
 		SkiaShader.cpp \
 		Snapshot.cpp \
@@ -57,7 +58,7 @@
 
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DGL_GLEXT_PROTOTYPES
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui libRS libRScpp
+	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libGLESv2 libskia libui libRS libRScpp
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index a1cc2e8..57d1a4f 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -103,14 +103,9 @@
 void Caches::initExtensions() {
     if (mExtensions.hasDebugMarker()) {
         eventMark = glInsertEventMarkerEXT;
-        if ((drawDeferDisabled || drawReorderDisabled)) {
-            startMark = glPushGroupMarkerEXT;
-            endMark = glPopGroupMarkerEXT;
-        } else {
-            startMark = startMarkNull;
-            endMark = endMarkNull;
-        }
 
+        startMark = glPushGroupMarkerEXT;
+        endMark = glPopGroupMarkerEXT;
     } else {
         eventMark = eventMarkNull;
         startMark = startMarkNull;
@@ -229,16 +224,6 @@
             gradientCache.getSize(), gradientCache.getMaxSize());
     log.appendFormat("  PathCache            %8d / %8d\n",
             pathCache.getSize(), pathCache.getMaxSize());
-    log.appendFormat("  CircleShapeCache     %8d / %8d\n",
-            circleShapeCache.getSize(), circleShapeCache.getMaxSize());
-    log.appendFormat("  OvalShapeCache       %8d / %8d\n",
-            ovalShapeCache.getSize(), ovalShapeCache.getMaxSize());
-    log.appendFormat("  RoundRectShapeCache  %8d / %8d\n",
-            roundRectShapeCache.getSize(), roundRectShapeCache.getMaxSize());
-    log.appendFormat("  RectShapeCache       %8d / %8d\n",
-            rectShapeCache.getSize(), rectShapeCache.getMaxSize());
-    log.appendFormat("  ArcShapeCache        %8d / %8d\n",
-            arcShapeCache.getSize(), arcShapeCache.getMaxSize());
     log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
             dropShadowCache.getMaxSize());
     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
@@ -258,11 +243,6 @@
     total += gradientCache.getSize();
     total += pathCache.getSize();
     total += dropShadowCache.getSize();
-    total += roundRectShapeCache.getSize();
-    total += circleShapeCache.getSize();
-    total += ovalShapeCache.getSize();
-    total += rectShapeCache.getSize();
-    total += arcShapeCache.getSize();
     for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
         total += fontRenderer->getFontRendererSize(i);
     }
@@ -330,11 +310,7 @@
             fontRenderer->flush();
             textureCache.flush();
             pathCache.clear();
-            roundRectShapeCache.clear();
-            circleShapeCache.clear();
-            ovalShapeCache.clear();
-            rectShapeCache.clear();
-            arcShapeCache.clear();
+            tasks.stop();
             // fall through
         case kFlushMode_Layers:
             layerCache.clear();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ca699d5..63836c1 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -25,6 +25,9 @@
 
 #include <cutils/compiler.h>
 
+#include "thread/TaskProcessor.h"
+#include "thread/TaskManager.h"
+
 #include "FontRenderer.h"
 #include "GammaFontRenderer.h"
 #include "TextureCache.h"
@@ -33,7 +36,6 @@
 #include "GradientCache.h"
 #include "PatchCache.h"
 #include "ProgramCache.h"
-#include "ShapeCache.h"
 #include "PathCache.h"
 #include "TextDropShadowCache.h"
 #include "FboCache.h"
@@ -266,11 +268,6 @@
     GradientCache gradientCache;
     ProgramCache programCache;
     PathCache pathCache;
-    RoundRectShapeCache roundRectShapeCache;
-    CircleShapeCache circleShapeCache;
-    OvalShapeCache ovalShapeCache;
-    RectShapeCache rectShapeCache;
-    ArcShapeCache arcShapeCache;
     PatchCache patchCache;
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
@@ -278,6 +275,8 @@
 
     GammaFontRenderer* fontRenderer;
 
+    TaskManager tasks;
+
     Dither dither;
     Stencil stencil;
 
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 773fe82..46beb94 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -64,7 +64,7 @@
 #define DEBUG_PATCHES_EMPTY_VERTICES 0
 
 // Turn on to display debug info about shapes
-#define DEBUG_SHAPES 0
+#define DEBUG_PATHS 0
 
 // Turn on to display debug info about textures
 #define DEBUG_TEXTURES 0
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index a4e9950..fe51bf9 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "OpenGLRenderer"
 #define ATRACE_TAG ATRACE_TAG_VIEW
 
+#include <SkCanvas.h>
+
 #include <utils/Trace.h>
 
 #include "Debug.h"
@@ -32,15 +34,18 @@
 namespace android {
 namespace uirenderer {
 
+// Depth of the save stack at the beginning of batch playback at flush time
+#define FLUSH_SAVE_STACK_DEPTH 2
+
+/////////////////////////////////////////////////////////////////////////////////
+// Operation Batches
+/////////////////////////////////////////////////////////////////////////////////
+
 class DrawOpBatch {
 public:
-    DrawOpBatch() {
-        mOps.clear();
-    }
+    DrawOpBatch() { mOps.clear(); }
 
-    ~DrawOpBatch() {
-        mOps.clear();
-    }
+    virtual ~DrawOpBatch() { mOps.clear(); }
 
     void add(DrawOp* op) {
         // NOTE: ignore empty bounds special case, since we don't merge across those ops
@@ -48,8 +53,9 @@
         mOps.add(op);
     }
 
-    bool intersects(Rect& rect) {
+    virtual bool intersects(Rect& rect) {
         if (!rect.intersects(mBounds)) return false;
+
         for (unsigned int i = 0; i < mOps.size(); i++) {
             if (rect.intersects(mOps[i]->state.mBounds)) {
 #if DEBUG_DEFER
@@ -64,27 +70,221 @@
         return false;
     }
 
-    Vector<DrawOp*> mOps;
+    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty) {
+        DEFER_LOGD("replaying draw batch %p", this);
+
+        status_t status = DrawGlInfo::kStatusDone;
+        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+        for (unsigned int i = 0; i < mOps.size(); i++) {
+            DrawOp* op = mOps[i];
+
+            renderer.restoreDisplayState(op->state);
+
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+            renderer.eventMark(op->name());
+#endif
+            status |= op->applyDraw(renderer, dirty, 0);
+            logBuffer.writeCommand(0, op->name());
+        }
+        return status;
+    }
+
+    inline int count() const { return mOps.size(); }
 private:
+    Vector<DrawOp*> mOps;
     Rect mBounds;
 };
 
-void DeferredDisplayList::clear() {
+class StateOpBatch : public DrawOpBatch {
+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) {
+        DEFER_LOGD("replaying state op batch %p", this);
+        renderer.restoreDisplayState(mOp->state);
+
+        // use invalid save count because it won't be used at flush time - RestoreToCountOp is the
+        // only one to use it, and we don't use that class at flush time, instead calling
+        // renderer.restoreToCount directly
+        int saveCount = -1;
+        mOp->applyState(renderer, saveCount);
+        return DrawGlInfo::kStatusDone;
+    }
+
+private:
+    const StateOp* mOp;
+};
+
+class RestoreToCountBatch : public DrawOpBatch {
+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) {
+        DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount);
+
+        renderer.restoreDisplayState(mOp->state);
+        renderer.restoreToCount(mRestoreCount);
+        return DrawGlInfo::kStatusDone;
+    }
+
+private:
+    // we use the state storage for the RestoreToCountOp, but don't replay the op itself
+    const StateOp* mOp;
+    /*
+     * The count used here represents the flush() time saveCount. This is as opposed to the
+     * DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and
+     * (saveCount + mCount) respectively). Since the count is different from the original
+     * RestoreToCountOp, we don't store a pointer to the op, as elsewhere.
+     */
+    const int mRestoreCount;
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+// DeferredDisplayList
+/////////////////////////////////////////////////////////////////////////////////
+
+void DeferredDisplayList::resetBatchingState() {
     for (int i = 0; i < kOpBatch_Count; i++) {
         mBatchIndices[i] = -1;
     }
+}
+
+void DeferredDisplayList::clear() {
+    resetBatchingState();
+    mComplexClipStackStart = -1;
+
     for (unsigned int i = 0; i < mBatches.size(); i++) {
         delete mBatches[i];
     }
     mBatches.clear();
+    mSaveStack.clear();
 }
 
-void DeferredDisplayList::add(DrawOp* op, bool disallowReorder) {
-    if (CC_UNLIKELY(disallowReorder)) {
-        if (!mBatches.isEmpty()) {
-            mBatches[0]->add(op);
-            return;
+/////////////////////////////////////////////////////////////////////////////////
+// Operation adding
+/////////////////////////////////////////////////////////////////////////////////
+
+int DeferredDisplayList::getStateOpDeferFlags() const {
+    // For both clipOp and save(Layer)Op, we don't want to save drawing info, and only want to save
+    // the clip if we aren't recording a complex clip (and can thus trust it to be a rect)
+    return recordingComplexClip() ? 0 : kStateDeferFlag_Clip;
+}
+
+int DeferredDisplayList::getDrawOpDeferFlags() const {
+    return kStateDeferFlag_Draw | getStateOpDeferFlags();
+}
+
+/**
+ * When an clipping operation occurs that could cause a complex clip, record the operation and all
+ * subsequent clipOps, save/restores (if the clip flag is set). During a flush, instead of loading
+ * the clip from deferred state, we play back all of the relevant state operations that generated
+ * the complex clip.
+ *
+ * Note that we don't need to record the associated restore operation, since operations at defer
+ * time record whether they should store the renderer's current clip
+ */
+void DeferredDisplayList::addClip(OpenGLRenderer& renderer, ClipOp* op) {
+    if (recordingComplexClip() || op->canCauseComplexClip() || !renderer.hasRectToRectTransform()) {
+        DEFER_LOGD("%p Received complex clip operation %p", this, op);
+
+        // NOTE: defer clip op before setting mComplexClipStackStart so previous clip is recorded
+        storeStateOpBarrier(renderer, op);
+
+        if (!recordingComplexClip()) {
+            mComplexClipStackStart = renderer.getSaveCount() - 1;
+            DEFER_LOGD("    Starting complex clip region, start is %d", mComplexClipStackStart);
         }
+    }
+}
+
+/**
+ * For now, we record save layer operations as barriers in the batch list, preventing drawing
+ * operations from reordering around the saveLayer and it's associated restore()
+ *
+ * In the future, we should send saveLayer commands (if they can be played out of order) and their
+ * contained drawing operations to a seperate list of batches, so that they may draw at the
+ * beginning of the frame. This would avoid targetting and removing an FBO in the middle of a frame.
+ *
+ * saveLayer operations should be pulled to the beginning of the frame if the canvas doesn't have a
+ * complex clip, and if the flags (kClip_SaveFlag & kClipToLayer_SaveFlag) are set.
+ */
+void DeferredDisplayList::addSaveLayer(OpenGLRenderer& renderer,
+        SaveLayerOp* op, int newSaveCount) {
+    DEFER_LOGD("%p adding saveLayerOp %p, flags %x, new count %d",
+            this, op, op->getFlags(), newSaveCount);
+
+    storeStateOpBarrier(renderer, op);
+    mSaveStack.push(newSaveCount);
+}
+
+/**
+ * Takes save op and it's return value - the new save count - and stores it into the stream as a
+ * barrier if it's needed to properly modify a complex clip
+ */
+void DeferredDisplayList::addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount) {
+    int saveFlags = op->getFlags();
+    DEFER_LOGD("%p adding saveOp %p, flags %x, new count %d", this, op, saveFlags, newSaveCount);
+
+    if (recordingComplexClip() && (saveFlags & SkCanvas::kClip_SaveFlag)) {
+        // store and replay the save operation, as it may be needed to correctly playback the clip
+        DEFER_LOGD("    adding save barrier with new save count %d", newSaveCount);
+        storeStateOpBarrier(renderer, op);
+        mSaveStack.push(newSaveCount);
+    }
+}
+
+/**
+ * saveLayer() commands must be associated with a restoreToCount batch that will clean up and draw
+ * the layer in the deferred list
+ *
+ * other save() commands which occur as children of a snapshot with complex clip will be deferred,
+ * and must be restored
+ *
+ * Either will act as a barrier to draw operation reordering, as we want to play back layer
+ * save/restore and complex canvas modifications (including save/restore) in order.
+ */
+void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, StateOp* op,
+        int newSaveCount) {
+    DEFER_LOGD("%p addRestoreToCount %d", this, newSaveCount);
+
+    if (recordingComplexClip() && newSaveCount <= mComplexClipStackStart) {
+        mComplexClipStackStart = -1;
+        resetBatchingState();
+    }
+
+    if (mSaveStack.isEmpty() || newSaveCount > mSaveStack.top()) {
+        return;
+    }
+
+    while (!mSaveStack.isEmpty() && mSaveStack.top() >= newSaveCount) mSaveStack.pop();
+
+    storeRestoreToCountBarrier(renderer, op, mSaveStack.size() + FLUSH_SAVE_STACK_DEPTH);
+}
+
+void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
+    if (renderer.storeDisplayState(op->state, getDrawOpDeferFlags())) {
+        return; // quick rejected
+    }
+
+    op->onDrawOpDeferred(renderer);
+
+    if (CC_UNLIKELY(renderer.getCaches().drawReorderDisabled)) {
+        // TODO: elegant way to reuse batches?
         DrawOpBatch* b = new DrawOpBatch();
         b->add(op);
         mBatches.add(b);
@@ -138,39 +338,66 @@
     targetBatch->add(op);
 }
 
-status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
-        uint32_t level) {
-    ATRACE_CALL();
+void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) {
+    DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size());
+
+    renderer.storeDisplayState(op->state, getStateOpDeferFlags());
+    mBatches.add(new StateOpBatch(op));
+    resetBatchingState();
+}
+
+void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op,
+        int newSaveCount) {
+    DEFER_LOGD("%p adding restore to count %d barrier, pos %d",
+            this, newSaveCount, mBatches.size());
+
+    // store displayState for the restore operation, as it may be associated with a saveLayer that
+    // doesn't have kClip_SaveFlag set
+    renderer.storeDisplayState(op->state, getStateOpDeferFlags());
+    mBatches.add(new RestoreToCountBatch(op, newSaveCount));
+    resetBatchingState();
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+// Replay / flush
+/////////////////////////////////////////////////////////////////////////////////
+
+static status_t replayBatchList(Vector<DrawOpBatch*>& 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();
+    }
+    DEFER_LOGD("--flushed, drew %d batches (total %d ops)", batchList.size(), opCount);
+    return status;
+}
+
+status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
+    ATRACE_NAME("flush drawing commands");
     status_t status = DrawGlInfo::kStatusDone;
 
     if (isEmpty()) return status; // nothing to flush
+    renderer.restoreToCount(1);
 
     DEFER_LOGD("--flushing");
     renderer.eventMark("Flush");
 
+    // save and restore (with draw modifiers) so that reordering doesn't affect final state
     DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
-    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    int opCount = 0;
-    for (unsigned int i = 0; i < mBatches.size(); i++) {
-        DrawOpBatch* batch = mBatches[i];
-        for (unsigned int j = 0; j < batch->mOps.size(); j++) {
-            DrawOp* op = batch->mOps[j];
+    renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
-            renderer.restoreDisplayState(op->state);
+    // NOTE: depth of the save stack at this point, before playback, should be reflected in
+    // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly
+    status |= replayBatchList(mBatches, renderer, dirty);
 
-#if DEBUG_DEFER
-            op->output(2);
-#endif
-            status |= op->applyDraw(renderer, dirty, level,
-                    op->state.mMultipliedAlpha >= 0, op->state.mMultipliedAlpha);
-            opCount++;
-        }
-    }
-
-    DEFER_LOGD("--flushed, drew %d batches (total %d ops)", mBatches.size(), opCount);
-
-    renderer.restoreToCount(restoreTo);
+    renderer.restoreToCount(1);
     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 4fcb297..653f315 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -26,10 +26,13 @@
 namespace android {
 namespace uirenderer {
 
+class ClipOp;
 class DrawOp;
+class SaveOp;
+class SaveLayerOp;
+class StateOp;
 class DrawOpBatch;
 class OpenGLRenderer;
-class SkiaShader;
 
 class DeferredDisplayList {
 public:
@@ -55,18 +58,43 @@
      * Plays back all of the draw ops recorded into batches to the renderer.
      * Adjusts the state of the renderer as necessary, and restores it when complete
      */
-    status_t flush(OpenGLRenderer& renderer, Rect& dirty, int32_t flags,
-            uint32_t level);
+    status_t flush(OpenGLRenderer& renderer, Rect& dirty);
+
+    void addClip(OpenGLRenderer& renderer, ClipOp* op);
+    void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount);
+    void addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount);
+    void addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, int newSaveCount);
 
     /**
      * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if
      * disallowReorder is false, respecting draw order when overlaps occur
      */
-    void add(DrawOp* op, bool disallowReorder);
+    void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
 
 private:
+    /**
+     * Resets the batching back-pointers, creating a barrier in the operation stream so that no ops
+     * added in the future will be inserted into a batch that already exist.
+     */
+    void resetBatchingState();
+
     void clear();
 
+    void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op);
+    void storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, int newSaveCount);
+
+    bool recordingComplexClip() const { return mComplexClipStackStart >= 0; }
+
+    int getStateOpDeferFlags() const;
+    int getDrawOpDeferFlags() const;
+
+    /**
+     * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so
+     * that when an associated restoreToCount is deferred, it can be recorded as a
+     * RestoreToCountBatch
+     */
+    Vector<int> mSaveStack;
+    int mComplexClipStackStart;
 
     Vector<DrawOpBatch*> mBatches;
     int mBatchIndices[kOpBatch_Count];
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index bdd539e..36c95f9 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <SkCanvas.h>
+
 #include "Debug.h"
 #include "DisplayList.h"
 #include "DisplayListOp.h"
@@ -61,6 +63,12 @@
 
 void DisplayList::clearResources() {
     mDisplayListData = NULL;
+
+    mClipRectOp = NULL;
+    mSaveLayerOp = NULL;
+    mSaveOp = NULL;
+    mRestoreToCountOp = NULL;
+
     delete mTransformMatrix;
     delete mTransformCamera;
     delete mTransformMatrix3D;
@@ -115,9 +123,7 @@
     }
 
     for (size_t i = 0; i < mPaths.size(); i++) {
-        SkPath* path = mPaths.itemAt(i);
-        caches.pathCache.remove(path);
-        delete path;
+        delete mPaths.itemAt(i);
     }
 
     for (size_t i = 0; i < mMatrices.size(); i++) {
@@ -156,6 +162,13 @@
         return;
     }
 
+    // allocate reusable ops for state-deferral
+    LinearAllocator& alloc = mDisplayListData->allocator;
+    mClipRectOp = new (alloc) ClipRectOp();
+    mSaveLayerOp = new (alloc) SaveLayerOp();
+    mSaveOp = new (alloc) SaveOp();
+    mRestoreToCountOp = new (alloc) RestoreToCountOp();
+
     mFunctorCount = recorder.getFunctorCount();
 
     Caches& caches = Caches::getInstance();
@@ -220,7 +233,6 @@
     mBottom = 0;
     mClipChildren = true;
     mAlpha = 1;
-    mMultipliedAlpha = 255;
     mHasOverlappingRendering = true;
     mTranslationX = 0;
     mTranslationY = 0;
@@ -318,7 +330,7 @@
     }
 }
 
-void DisplayList::outputViewProperties(uint32_t level) {
+void DisplayList::outputViewProperties(const int level) {
     updateMatrix();
     if (mLeft != 0 || mTop != 0) {
         ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
@@ -339,9 +351,11 @@
                     level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
         }
     }
-    if (mAlpha < 1 && !mCaching) {
-        if (!mHasOverlappingRendering) {
-            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
+    if (mAlpha < 1) {
+        if (mCaching) {
+            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
+        } else if (!mHasOverlappingRendering) {
+            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
         } else {
             int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
             if (mClipChildren) {
@@ -349,7 +363,7 @@
             }
             ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
                     (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
-                    mMultipliedAlpha, flags);
+                    (int)(mAlpha * 255), flags);
         }
     }
     if (mClipChildren && !mCaching) {
@@ -358,10 +372,17 @@
     }
 }
 
-status_t DisplayList::setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
-        int32_t flags, uint32_t level, DeferredDisplayList* deferredList) {
-    status_t status = DrawGlInfo::kStatusDone;
-#if DEBUG_DISPLAYLIST
+/*
+ * For property operations, we pass a savecount of 0, since the operations aren't part of the
+ * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
+ * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
+ */
+#define PROPERTY_SAVECOUNT 0
+
+template <class T>
+void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
+        const int level) {
+#if DEBUG_DISPLAY_LIST
     outputViewProperties(level);
 #endif
     updateMatrix();
@@ -380,88 +401,123 @@
             renderer.concatMatrix(mTransformMatrix);
         }
     }
-    if (mAlpha < 1 && !mCaching) {
-        if (deferredList) {
-            // flush since we'll either enter a Layer, or set alpha, both not supported in deferral
-            status |= deferredList->flush(renderer, dirty, flags, level);
-        }
-
-        if (!mHasOverlappingRendering) {
-            renderer.setAlpha(mAlpha);
+    if (mAlpha < 1) {
+        if (mCaching) {
+            renderer.setOverrideLayerAlpha(mAlpha);
+        } else if (!mHasOverlappingRendering) {
+            renderer.scaleAlpha(mAlpha);
         } else {
             // TODO: should be able to store the size of a DL at record time and not
             // have to pass it into this call. In fact, this information might be in the
             // location/size info that we store with the new native transform data.
-            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
             if (mClipChildren) {
-                flags |= SkCanvas::kClipToLayer_SaveFlag;
+                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
             }
-            renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
-                    mMultipliedAlpha, flags);
+            handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
+                    mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT);
         }
     }
     if (mClipChildren && !mCaching) {
-        if (deferredList && CC_UNLIKELY(!renderer.hasRectToRectTransform())) {
-            // flush, since clip will likely be a region
-            status |= deferredList->flush(renderer, dirty, flags, level);
-        }
-        renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
-                SkRegion::kIntersect_Op);
+        handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
+                PROPERTY_SAVECOUNT);
     }
-    return status;
 }
 
-status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
-        DeferredDisplayList* deferredList) {
-    status_t drawGlStatus = DrawGlInfo::kStatusDone;
+class DeferOperationHandler {
+public:
+    DeferOperationHandler(DeferStateStruct& deferStruct, int level)
+        : mDeferStruct(deferStruct), mLevel(level) {}
+    inline void operator()(DisplayListOp* operation, int saveCount) {
+        operation->defer(mDeferStruct, saveCount, mLevel);
+    }
+private:
+    DeferStateStruct& mDeferStruct;
+    const int mLevel;
+};
+
+void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
+    DeferOperationHandler handler(deferStruct, level);
+    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
+}
+
+class ReplayOperationHandler {
+public:
+    ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
+        : mReplayStruct(replayStruct), mLevel(level) {}
+    inline void operator()(DisplayListOp* operation, int saveCount) {
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+        mReplayStruct.mRenderer.eventMark(operation->name());
+#endif
+        operation->replay(mReplayStruct, saveCount, mLevel);
+    }
+private:
+    ReplayStateStruct& mReplayStruct;
+    const int mLevel;
+};
+
+void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
+    ReplayOperationHandler handler(replayStruct, level);
+
+    replayStruct.mRenderer.startMark(mName.string());
+    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
+    replayStruct.mRenderer.endMark();
+
+    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
+            replayStruct.mDrawGlStatus);
+}
+
+/**
+ * This function serves both defer and replay modes, and will organize the displayList's component
+ * operations for a single frame:
+ *
+ * Every 'simple' operation that affects just the matrix and alpha (or other factors of
+ * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
+ * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
+ * defer vs replay logic, per operation
+ */
+template <class T>
+void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
+    if (mSize == 0 || mAlpha <= 0) {
+        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
+        return;
+    }
 
 #if DEBUG_DISPLAY_LIST
     Rect* clipRect = renderer.getClipRect();
     DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
-            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
+            level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
             clipRect->right, clipRect->bottom);
 #endif
 
-    renderer.startMark(mName.string());
+    int restoreTo = renderer.getSaveCount();
+    handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+            PROPERTY_SAVECOUNT);
 
-    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
+    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
 
-    drawGlStatus |= setViewProperties(renderer, dirty, flags, level, deferredList);
+    setViewProperties<T>(renderer, handler, level + 1);
 
     if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
         DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
-        renderer.restoreToCount(restoreTo);
-        renderer.endMark();
-        return drawGlStatus;
+        handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT);
+        return;
     }
 
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     int saveCount = renderer.getSaveCount() - 1;
     for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
         DisplayListOp *op = mDisplayListData->displayListOps[i];
-#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
-        Caches::getInstance().eventMark(strlen(op->name()), op->name());
-#endif
 
-        drawGlStatus |= op->replay(renderer, dirty, flags,
-                saveCount, level, mCaching, mMultipliedAlpha, deferredList);
+        handler(op, saveCount);
         logBuffer.writeCommand(level, op->name());
     }
 
-    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
+    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
+    handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT);
     renderer.restoreToCount(restoreTo);
-    renderer.endMark();
-
-    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
-            drawGlStatus);
-
-    if (!level && CC_LIKELY(deferredList)) {
-        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
-    }
-
-    return drawGlStatus;
+    renderer.setOverrideLayerAlpha(1.0f);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index feee69c..84f20ab 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -24,6 +24,8 @@
 #include <SkCamera.h>
 #include <SkMatrix.h>
 
+#include <private/hwui/DrawGlInfo.h>
+
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
@@ -57,10 +59,33 @@
 class SkiaColorFilter;
 class SkiaShader;
 
+class ClipRectOp;
+class SaveLayerOp;
+class SaveOp;
+class RestoreToCountOp;
+
+struct DeferStateStruct {
+    DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
+            : mDeferredList(deferredList), mRenderer(renderer), mReplayFlags(replayFlags) {}
+    DeferredDisplayList& mDeferredList;
+    OpenGLRenderer& mRenderer;
+    const int mReplayFlags;
+};
+
+struct ReplayStateStruct {
+    ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
+            : mRenderer(renderer), mDirty(dirty), mReplayFlags(replayFlags),
+            mDrawGlStatus(DrawGlInfo::kStatusDone) {}
+    OpenGLRenderer& mRenderer;
+    Rect& mDirty;
+    const int mReplayFlags;
+    status_t mDrawGlStatus;
+};
+
 /**
  * Refcounted structure that holds data used in display list stream
  */
-class DisplayListData: public LightRefBase<DisplayListData> {
+class DisplayListData : public LightRefBase<DisplayListData> {
 public:
     LinearAllocator allocator;
     Vector<DisplayListOp*> displayListOps;
@@ -79,9 +104,6 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    status_t setViewProperties(OpenGLRenderer& renderer, Rect& dirty,
-            int32_t flags, uint32_t level, DeferredDisplayList* deferredList);
-    void outputViewProperties(uint32_t level);
 
     ANDROID_API size_t getSize();
     ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
@@ -89,8 +111,9 @@
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
-    status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0,
-            DeferredDisplayList* deferredList = NULL);
+
+    void defer(DeferStateStruct& deferStruct, const int level);
+    void replay(ReplayStateStruct& replayStruct, const int level);
 
     void output(uint32_t level = 0);
 
@@ -141,7 +164,6 @@
         alpha = fminf(1.0f, fmaxf(0.0f, alpha));
         if (alpha != mAlpha) {
             mAlpha = alpha;
-            mMultipliedAlpha = (int) (255 * alpha);
         }
     }
 
@@ -426,6 +448,14 @@
     }
 
 private:
+    void outputViewProperties(const int level);
+
+    template <class T>
+    inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
+
+    template <class T>
+    inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
+
     void init();
 
     void clearResources();
@@ -470,7 +500,6 @@
     // View properties
     bool mClipChildren;
     float mAlpha;
-    int mMultipliedAlpha;
     bool mHasOverlappingRendering;
     float mTranslationX, mTranslationY;
     float mRotation, mRotationX, mRotationY;
@@ -490,6 +519,22 @@
     SkMatrix* mStaticMatrix;
     SkMatrix* mAnimationMatrix;
     bool mCaching;
+
+    /**
+     * State operations - needed to defer displayList property operations (for example, when setting
+     * an alpha causes a SaveLayerAlpha to occur). These operations point into mDisplayListData's
+     * allocation, or null if uninitialized.
+     *
+     * These are initialized (via friend constructors) when a displayList is issued in either replay
+     * or deferred mode. If replaying, the ops are not used until the next frame. If deferring, the
+     * ops may be stored in the DeferredDisplayList to be played back a second time.
+     *
+     * They should be used at most once per frame (one call to iterate)
+     */
+    ClipRectOp* mClipRectOp;
+    SaveLayerOp* mSaveLayerOp;
+    SaveOp* mSaveOp;
+    RestoreToCountOp* mRestoreToCountOp;
 }; // class DisplayList
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index d231907..a5dee9f 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -78,17 +78,24 @@
         kOpLogFlag_JSON = 0x2 // TODO: add?
     };
 
-    // If a DeferredDisplayList is supplied, DrawOps will be stored until the list is flushed
-    // NOTE: complex clips and layers prevent deferral
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha,
-            DeferredDisplayList* deferredList) = 0;
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) = 0;
 
-    virtual void output(int level, uint32_t flags = 0) = 0;
+    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) = 0;
+
+    virtual void output(int level, uint32_t logFlags = 0) = 0;
 
     // NOTE: it would be nice to declare constants and overriding the implementation in each op to
     // point at the constants, but that seems to require a .cpp file
     virtual const char* name() = 0;
+
+    /**
+     * Stores the relevant canvas state of the object between deferral and replay (if the canvas
+     * state supports being stored) See OpenGLRenderer::simpleClipAndState()
+     *
+     * TODO: don't reserve space for StateOps that won't be deferred
+     */
+    DeferredDisplayState state;
+
 };
 
 class StateOp : public DisplayListOp {
@@ -97,28 +104,20 @@
 
     virtual ~StateOp() {}
 
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
+        // default behavior only affects immediate, deferrable state, issue directly to renderer
+        applyState(deferStruct.mRenderer, saveCount);
+    }
+
     /**
      * State operations are applied directly to the renderer, but can cause the deferred drawing op
      * list to flush
      */
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
-        status_t status = DrawGlInfo::kStatusDone;
-        if (deferredList && requiresDrawOpFlush(renderer)) {
-            // will be setting renderer state that affects ops in deferredList, so flush list first
-            status |= deferredList->flush(renderer, dirty, flags, level);
-        }
-        applyState(renderer, saveCount);
-        return status;
+    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
+        applyState(replayStruct.mRenderer, saveCount);
     }
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
-
-    /**
-     * Returns true if it affects renderer drawing state in such a way to break deferral
-     * see OpenGLRenderer::disallowDeferral()
-     */
-    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return false; }
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0;
 };
 
 class DrawOp : public DisplayListOp {
@@ -126,36 +125,30 @@
     DrawOp(SkPaint* paint)
             : mPaint(paint), mQuickRejected(false) {}
 
-    /** Draw operations are stored in the deferredList with information necessary for playback */
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
-        if (mQuickRejected && CC_LIKELY(flags & DisplayList::kReplayFlag_ClipChildren)) {
-            return DrawGlInfo::kStatusDone;
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
+        if (mQuickRejected &&
+                CC_LIKELY(deferStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
+            return;
         }
 
-        if (!deferredList || renderer.disallowDeferral()) {
-            // dispatch draw immediately, since the renderer's state is too complex for deferral
-            return applyDraw(renderer, dirty, level, caching, multipliedAlpha);
-        }
-
-        if (!caching) multipliedAlpha = -1;
-        state.mMultipliedAlpha = multipliedAlpha;
         if (!getLocalBounds(state.mBounds)) {
             // empty bounds signify bounds can't be calculated
             state.mBounds.setEmpty();
         }
 
-        if (!renderer.storeDisplayState(state)) {
-            // op wasn't quick-rejected, so defer
-            deferredList->add(this, renderer.getCaches().drawReorderDisabled);
-            onDrawOpDeferred(renderer);
-        }
-
-        return DrawGlInfo::kStatusDone;
+        deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) = 0;
+    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
+        if (mQuickRejected &&
+                CC_LIKELY(replayStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
+            return;
+        }
+
+        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty, level);
+    }
+
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) = 0;
 
     virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
     }
@@ -172,16 +165,15 @@
         return DeferredDisplayList::kOpBatch_None;
     }
 
-    float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
+    float strokeWidthOutset() {
+        float width = mPaint->getStrokeWidth();
+        if (width == 0) return 0.5f; // account for hairline
+        return width * 0.5f;
+    }
 
-    /**
-     * Stores the relevant canvas state of the object between deferral and replay (if the canvas
-     * state supports being stored) See OpenGLRenderer::simpleClipAndState()
-     */
-    DeferredDisplayState state;
 protected:
-    SkPaint* getPaint(OpenGLRenderer& renderer, bool alwaysCopy = false) {
-        return renderer.filterPaint(mPaint, alwaysCopy);
+    SkPaint* getPaint(OpenGLRenderer& renderer) {
+        return renderer.filterPaint(mPaint);
     }
 
     SkPaint* mPaint; // should be accessed via getPaint() when applying
@@ -225,88 +217,116 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class SaveOp : public StateOp {
+    friend class DisplayList; // give DisplayList private constructor/reinit access
 public:
     SaveOp(int flags)
             : mFlags(flags) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
+        int newSaveCount = deferStruct.mRenderer.save(mFlags);
+        deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
+    }
+
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.save(mFlags);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Save flags %x", mFlags);
     }
 
     virtual const char* name() { return "Save"; }
 
+    int getFlags() const { return mFlags; }
 private:
+    SaveOp() {}
+    DisplayListOp* reinit(int flags) {
+        mFlags = flags;
+        return this;
+    }
+
     int mFlags;
 };
 
 class RestoreToCountOp : public StateOp {
+    friend class DisplayList; // give DisplayList private constructor/reinit access
 public:
     RestoreToCountOp(int count)
             : mCount(count) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
-        renderer.restoreToCount(saveCount + mCount);
-
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
+        deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
+                this, saveCount + mCount);
+        deferStruct.mRenderer.restoreToCount(saveCount + mCount);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+        renderer.restoreToCount(saveCount + mCount);
+    }
+
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Restore to count %d", mCount);
     }
 
     virtual const char* name() { return "RestoreToCount"; }
-    // Note: don't have to return true for requiresDrawOpFlush - even though restore can create a
-    // complex clip, the clip and matrix are overridden by DeferredDisplayList::flush()
 
 private:
+    RestoreToCountOp() {}
+    DisplayListOp* reinit(int count) {
+        mCount = count;
+        return this;
+    }
+
     int mCount;
 };
 
 class SaveLayerOp : public StateOp {
+    friend class DisplayList; // give DisplayList private constructor/reinit access
 public:
-    SaveLayerOp(float left, float top, float right, float bottom, SkPaint* paint, int flags)
-            : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
+    SaveLayerOp(float left, float top, float right, float bottom,
+            int alpha, SkXfermode::Mode mode, int flags)
+            : mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
-        SkPaint* paint = renderer.filterPaint(mPaint);
-        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, paint, mFlags);
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
+        // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
+        int newSaveCount = deferStruct.mRenderer.getSaveCount();
+        deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
+
+        // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
+        // setup the snapshot for deferral, and re-issue the op at flush time
+        deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
+                mAlpha, mMode, mFlags);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
-        OP_LOG("SaveLayer of area " RECT_STRING, RECT_ARGS(mArea));
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
     }
 
-    virtual const char* name() { return "SaveLayer"; }
-    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
+    virtual void output(int level, uint32_t logFlags) {
+        OP_LOG("SaveLayer%s of area " RECT_STRING,
+                (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
+    }
+
+    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
+
+    int getFlags() { return mFlags; }
 
 private:
-    Rect mArea;
-    SkPaint* mPaint;
-    int mFlags;
-};
-
-class SaveLayerAlphaOp : public StateOp {
-public:
-    SaveLayerAlphaOp(float left, float top, float right, float bottom, int alpha, int flags)
-            : mArea(left, top, right, bottom), mAlpha(alpha), mFlags(flags) {}
-
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
-        renderer.saveLayerAlpha(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mFlags);
+    // Special case, reserved for direct DisplayList usage
+    SaveLayerOp() {}
+    DisplayListOp* reinit(float left, float top, float right, float bottom,
+            int alpha, SkXfermode::Mode mode, int flags) {
+        mArea.set(left, top, right, bottom);
+        mAlpha = alpha;
+        mMode = mode;
+        mFlags = flags;
+        return this;
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
-        OP_LOG("SaveLayerAlpha of area " RECT_STRING, RECT_ARGS(mArea));
-    }
-
-    virtual const char* name() { return "SaveLayerAlpha"; }
-    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
-
-private:
+    bool isSaveLayerAlpha() { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
     Rect mArea;
     int mAlpha;
+    SkXfermode::Mode mMode;
     int mFlags;
 };
 
@@ -315,11 +335,11 @@
     TranslateOp(float dx, float dy)
             : mDx(dx), mDy(dy) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.translate(mDx, mDy);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Translate by %f %f", mDx, mDy);
     }
 
@@ -335,11 +355,11 @@
     RotateOp(float degrees)
             : mDegrees(degrees) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.rotate(mDegrees);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Rotate by %f degrees", mDegrees);
     }
 
@@ -354,11 +374,11 @@
     ScaleOp(float sx, float sy)
             : mSx(sx), mSy(sy) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.scale(mSx, mSy);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Scale by %f %f", mSx, mSy);
     }
 
@@ -374,11 +394,11 @@
     SkewOp(float sx, float sy)
             : mSx(sx), mSy(sy) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.skew(mSx, mSy);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Skew by %f %f", mSx, mSy);
     }
 
@@ -394,11 +414,11 @@
     SetMatrixOp(SkMatrix* matrix)
             : mMatrix(matrix) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.setMatrix(mMatrix);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
     }
 
@@ -413,11 +433,11 @@
     ConcatMatrixOp(SkMatrix* matrix)
             : mMatrix(matrix) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.concatMatrix(mMatrix);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
     }
 
@@ -427,75 +447,96 @@
     SkMatrix* mMatrix;
 };
 
-class ClipRectOp : public StateOp {
+class ClipOp : public StateOp {
+public:
+    ClipOp(SkRegion::Op op) : mOp(op) {}
+
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
+        // NOTE: must defer op BEFORE applying state, since it may read clip
+        deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
+
+        // TODO: Can we avoid applying complex clips at defer time?
+        applyState(deferStruct.mRenderer, saveCount);
+    }
+
+    bool canCauseComplexClip() {
+        return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
+    }
+
+protected:
+    ClipOp() {}
+    virtual bool isRect() { return false; }
+
+    SkRegion::Op mOp;
+};
+
+class ClipRectOp : public ClipOp {
+    friend class DisplayList; // give DisplayList private constructor/reinit access
 public:
     ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
-            : mArea(left, top, right, bottom), mOp(op) {}
+            : ClipOp(op), mArea(left, top, right, bottom) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
     }
 
     virtual const char* name() { return "ClipRect"; }
 
-    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) {
-        // TODO: currently, we flush when we *might* cause a clip region to exist. Ideally, we
-        // should only flush when a non-rectangular clip would result
-        return !renderer.hasRectToRectTransform() || !hasRectToRectOp();
-    }
+protected:
+    virtual bool isRect() { return true; }
 
 private:
-    inline bool hasRectToRectOp() {
-        return mOp == SkRegion::kIntersect_Op || mOp == SkRegion::kReplace_Op;
+    ClipRectOp() {}
+    DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
+        mOp = op;
+        mArea.set(left, top, right, bottom);
+        return this;
     }
+
     Rect mArea;
-    SkRegion::Op mOp;
 };
 
-class ClipPathOp : public StateOp {
+class ClipPathOp : public ClipOp {
 public:
     ClipPathOp(SkPath* path, SkRegion::Op op)
-            : mPath(path), mOp(op) {}
+            : ClipOp(op), mPath(path) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.clipPath(mPath, mOp);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         SkRect bounds = mPath->getBounds();
         OP_LOG("ClipPath bounds " RECT_STRING,
                 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
     }
 
     virtual const char* name() { return "ClipPath"; }
-    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     SkPath* mPath;
-    SkRegion::Op mOp;
 };
 
-class ClipRegionOp : public StateOp {
+class ClipRegionOp : public ClipOp {
 public:
     ClipRegionOp(SkRegion* region, SkRegion::Op op)
-            : mRegion(region), mOp(op) {}
+            : ClipOp(op), mRegion(region) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.clipRegion(mRegion, mOp);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         SkIRect bounds = mRegion->getBounds();
         OP_LOG("ClipRegion bounds %d %d %d %d",
                 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
     }
 
     virtual const char* name() { return "ClipRegion"; }
-    virtual bool requiresDrawOpFlush(OpenGLRenderer& renderer) { return true; }
 
 private:
     SkRegion* mRegion;
@@ -504,11 +545,11 @@
 
 class ResetShaderOp : public StateOp {
 public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.resetShader();
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOGS("ResetShader");
     }
 
@@ -519,11 +560,11 @@
 public:
     SetupShaderOp(SkiaShader* shader)
             : mShader(shader) {}
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.setupShader(mShader);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("SetupShader, shader %p", mShader);
     }
 
@@ -535,11 +576,11 @@
 
 class ResetColorFilterOp : public StateOp {
 public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.resetColorFilter();
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOGS("ResetColorFilter");
     }
 
@@ -551,11 +592,11 @@
     SetupColorFilterOp(SkiaColorFilter* colorFilter)
             : mColorFilter(colorFilter) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.setupColorFilter(mColorFilter);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("SetupColorFilter, filter %p", mColorFilter);
     }
 
@@ -567,11 +608,11 @@
 
 class ResetShadowOp : public StateOp {
 public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.resetShadow();
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOGS("ResetShadow");
     }
 
@@ -583,11 +624,11 @@
     SetupShadowOp(float radius, float dx, float dy, int color)
             : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.setupShadow(mRadius, mDx, mDy, mColor);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
     }
 
@@ -602,11 +643,11 @@
 
 class ResetPaintFilterOp : public StateOp {
 public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.resetPaintFilter();
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOGS("ResetPaintFilter");
     }
 
@@ -618,11 +659,11 @@
     SetupPaintFilterOp(int clearBits, int setBits)
             : mClearBits(clearBits), mSetBits(setBits) {}
 
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
+    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
         renderer.setupPaintFilter(mClearBits, mSetBits);
     }
 
-    virtual void output(int level, uint32_t flags = 0) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
     }
 
@@ -645,19 +686,12 @@
                     paint),
             mBitmap(bitmap) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
-        bool makeCopy = caching && multipliedAlpha < 255;
-        SkPaint* paint = getPaint(renderer, makeCopy);
-        if (makeCopy) {
-            // The paint is safe to modify since we're working on a copy
-            paint->setAlpha(multipliedAlpha);
-        }
-        status_t ret = renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top, paint);
-        return ret;
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+        return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
+                getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
     }
 
@@ -679,12 +713,11 @@
         transform.mapRect(mLocalBounds);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
     }
 
@@ -705,14 +738,13 @@
             : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
             mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
                 mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
                 getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
                 mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
     }
@@ -732,13 +764,12 @@
     DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
             : DrawBitmapOp(bitmap, left, top, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
                 mLocalBounds.top, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw bitmap %p", mBitmap);
     }
 
@@ -756,13 +787,12 @@
             mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
             mVertices(vertices), mColors(colors) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
                 mVertices, mColors, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
     }
 
@@ -790,8 +820,7 @@
             mColors(colors), mxDivsCount(width), myDivsCount(height),
             mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         // NOTE: not calling the virtual method, which takes a paint
         return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
                 mxDivsCount, myDivsCount, mNumColors,
@@ -799,7 +828,7 @@
                 mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
@@ -825,12 +854,11 @@
     DrawColorOp(int color, SkXfermode::Mode mode)
             : DrawOp(0), mColor(color), mMode(mode) {};
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawColor(mColor, mMode);
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw color %#x, mode %d", mColor, mMode);
     }
 
@@ -869,13 +897,12 @@
     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, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
@@ -888,12 +915,11 @@
             : DrawBoundedOp(rects, count, paint),
             mRects(rects), mCount(count) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawRects(mRects, mCount, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Rects count %d", mCount);
     }
 
@@ -914,13 +940,12 @@
             float rx, float ry, SkPaint* paint)
             : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
     }
 
@@ -937,12 +962,11 @@
             : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
             mX(x), mY(y), mRadius(radius) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
     }
 
@@ -959,13 +983,12 @@
     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, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
     }
 
@@ -979,14 +1002,13 @@
             : DrawStrokableOp(left, top, right, bottom, paint),
             mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
                 mLocalBounds.right, mLocalBounds.bottom,
                 mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
                 RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
     }
@@ -1005,18 +1027,22 @@
             : DrawBoundedOp(paint), mPath(path) {
         float left, top, offset;
         uint32_t width, height;
-        computePathBounds(path, paint, left, top, offset, width, height);
+        PathCache::computePathBounds(path, paint, left, top, offset, width, height);
         left -= offset;
         top -= offset;
         mLocalBounds.set(left, top, left + width, top + height);
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawPath(mPath, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
+        SkPaint* paint = getPaint(renderer);
+        renderer.getCaches().pathCache.precache(mPath, paint);
+    }
+
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
     }
 
@@ -1037,12 +1063,11 @@
         mLocalBounds.outset(strokeWidthOutset());
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawLines(mPoints, mCount, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Lines count %d", mCount);
     }
 
@@ -1064,12 +1089,11 @@
     DrawPointsOp(float* points, int count, SkPaint* paint)
             : DrawLinesOp(points, count, paint) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Points count %d", mCount);
     }
 
@@ -1081,7 +1105,7 @@
     DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
             : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
@@ -1111,8 +1135,7 @@
         /* TODO: inherit from DrawBounded and init mLocalBounds */
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
                 mHOffset, mVOffset, getPaint(renderer));
     }
@@ -1133,8 +1156,7 @@
         /* TODO: inherit from DrawBounded and init mLocalBounds */
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
     }
 
@@ -1164,6 +1186,7 @@
             break;
         }
         mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
+        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
     }
 
     /*
@@ -1174,18 +1197,19 @@
     virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
         SkPaint* paint = getPaint(renderer);
         FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
-        const bool pureTranslate = state.mMatrix.isPureTranslate();
-        const mat4 transform = renderer.findBestFontTransform(state.mMatrix);
-        fontRenderer.precache(paint, mText, mCount, transform);
+        const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
+        if (mPrecacheTransform != transform) {
+            fontRenderer.precache(paint, mText, mCount, transform);
+            mPrecacheTransform = transform;
+        }
     }
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
                 mPositions, getPaint(renderer), mLength);
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
     }
 
@@ -1205,6 +1229,7 @@
     float mY;
     const float* mPositions;
     float mLength;
+    mat4 mPrecacheTransform;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1216,15 +1241,14 @@
     DrawFunctorOp(Functor* functor)
             : DrawOp(0), mFunctor(functor) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
         renderer.startMark("GL functor");
         status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
         renderer.endMark();
         return ret;
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Functor %p", mFunctor);
     }
 
@@ -1240,21 +1264,25 @@
             : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
             mDisplayList(displayList), mFlags(flags) {}
 
-    virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, int saveCount,
-            uint32_t level, bool caching, int multipliedAlpha, DeferredDisplayList* deferredList) {
+    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
         if (mDisplayList && mDisplayList->isRenderable()) {
-            return mDisplayList->replay(renderer, dirty, mFlags, level + 1, deferredList);
+            mDisplayList->defer(deferStruct, level + 1);
         }
+    }
+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) {
         return DrawGlInfo::kStatusDone;
     }
 
-    // NOT USED, since replay is overridden
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) { return DrawGlInfo::kStatusDone; }
-
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
-        if (mDisplayList && (flags & kOpLogFlag_Recurse)) {
+        if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
             mDisplayList->output(level + 1);
         }
     }
@@ -1268,25 +1296,14 @@
 
 class DrawLayerOp : public DrawOp {
 public:
-    DrawLayerOp(Layer* layer, float x, float y, SkPaint* paint)
-            : DrawOp(paint), mLayer(layer), mX(x), mY(y) {}
+    DrawLayerOp(Layer* layer, float x, float y)
+            : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
 
-    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, uint32_t level,
-            bool caching, int multipliedAlpha) {
-        int oldAlpha = -1;
-
-        if (caching && multipliedAlpha < 255) {
-            oldAlpha = mLayer->getAlpha();
-            mLayer->setAlpha(multipliedAlpha);
-        }
-        status_t ret = renderer.drawLayer(mLayer, mX, mY, getPaint(renderer));
-        if (oldAlpha >= 0) {
-            mLayer->setAlpha(oldAlpha);
-        }
-        return ret;
+    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+        return renderer.drawLayer(mLayer, mX, mY);
     }
 
-    virtual void output(int level, uint32_t flags) {
+    virtual void output(int level, uint32_t logFlags) {
         OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
     }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index b011443..0b8f7e6 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include <SkCamera.h>
+#include <SkCanvas.h>
 
 #include <private/hwui/DrawGlInfo.h>
 
@@ -175,14 +176,8 @@
 }
 
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
-        SkPaint* p, int flags) {
-    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, p, flags));
-    return OpenGLRenderer::save(flags);
-}
-
-int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
-        int alpha, int flags) {
-    addStateOp(new (alloc()) SaveLayerAlphaOp(left, top, right, bottom, alpha, flags));
+        int alpha, SkXfermode::Mode mode, int flags) {
+    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags));
     return OpenGLRenderer::save(flags);
 }
 
@@ -252,12 +247,9 @@
     return DrawGlInfo::kStatusDone;
 }
 
-status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
-    mLayers.add(layer);
-    mCaches.resourceCache.incrementRefcount(layer);
-    paint = refPaint(paint);
-
-    addDrawOp(new (alloc()) DrawLayerOp(layer, x, y, paint));
+status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y) {
+    layer = refLayer(layer);
+    addDrawOp(new (alloc()) DrawLayerOp(layer, x, y));
     return DrawGlInfo::kStatusDone;
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 38619bf..19f7eb6 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -79,9 +79,7 @@
     virtual void restoreToCount(int saveCount);
 
     virtual int saveLayer(float left, float top, float right, float bottom,
-            SkPaint* p, int flags);
-    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-                int alpha, int flags);
+            int alpha, SkXfermode::Mode mode, int flags);
 
     virtual void translate(float dx, float dy);
     virtual void rotate(float degrees);
@@ -96,7 +94,7 @@
     virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
 
     virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
-    virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
+    virtual status_t drawLayer(Layer* layer, float x, float y);
     virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
@@ -273,6 +271,12 @@
         return copy;
     }
 
+    inline Layer* refLayer(Layer* layer) {
+        mLayers.add(layer);
+        mCaches.resourceCache.incrementRefcount(layer);
+        return layer;
+    }
+
     inline SkBitmap* refBitmap(SkBitmap* bitmap) {
         // Note that this assumes the bitmap is immutable. There are cases this won't handle
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
old mode 100755
new mode 100644
index e80b325..51f1e39
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -21,38 +21,50 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-// Must be a power of two
-#define DITHER_KERNEL_SIZE 4
-
-///////////////////////////////////////////////////////////////////////////////
 // Lifecycle
 ///////////////////////////////////////////////////////////////////////////////
 
 void Dither::bindDitherTexture() {
     if (!mInitialized) {
-        const uint8_t pattern[] = {
-             0,  8,  2, 10,
-            12,  4, 14,  6,
-             3, 11,  1,  9,
-            15,  7, 13,  5
-        };
+        bool useFloatTexture = Extensions::getInstance().getMajorGlVersion() >= 3;
 
         glGenTextures(1, &mDitherTexture);
         glBindTexture(GL_TEXTURE_2D, mDitherTexture);
 
-        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
-                GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
+        if (useFloatTexture) {
+            // We use a R16F texture, let's remap the alpha channel to the
+            // red channel to avoid changing the shader sampling code on GL ES 3.0+
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
+
+            float dither = 1.0f / (255.0f * DITHER_KERNEL_SIZE * DITHER_KERNEL_SIZE);
+            const GLfloat pattern[] = {
+                 0 * dither,  8 * dither,  2 * dither, 10 * dither,
+                12 * dither,  4 * dither, 14 * dither,  6 * dither,
+                 3 * dither, 11 * dither,  1 * dither,  9 * dither,
+                15 * dither,  7 * dither, 13 * dither,  5 * dither
+            };
+
+            glPixelStorei(GL_UNPACK_ALIGNMENT, sizeof(GLfloat));
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
+                    GL_RED, GL_FLOAT, &pattern);
+        } else {
+            const uint8_t pattern[] = {
+                 0,  8,  2, 10,
+                12,  4, 14,  6,
+                 3, 11,  1,  9,
+                15,  7, 13,  5
+            };
+
+            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
+                    GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
+        }
 
         mInitialized = true;
     } else {
@@ -76,10 +88,7 @@
 
     bindDitherTexture();
 
-    float ditherSize = 1.0f / DITHER_KERNEL_SIZE;
     glUniform1i(program->getUniform("ditherSampler"), textureSlot);
-    glUniform1f(program->getUniform("ditherSize"), ditherSize);
-    glUniform1f(program->getUniform("ditherSizeSquared"), ditherSize * ditherSize);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
old mode 100755
new mode 100644
index 34cf9bf..4d1f921
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -17,13 +17,23 @@
 #ifndef ANDROID_HWUI_DITHER_H
 #define ANDROID_HWUI_DITHER_H
 
-#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
 
 #include "Program.h"
 
 namespace android {
 namespace uirenderer {
 
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Must be a power of two
+#define DITHER_KERNEL_SIZE 4
+// These must not use the .0f notation as they are used from GLSL
+#define DITHER_KERNEL_SIZE_INV (1.0 / 4.0)
+#define DITHER_KERNEL_SIZE_INV_SQUARE (1.0 / 16.0)
+
 /**
  * Handles dithering for programs.
  */
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index edc90fb..51aec8d 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -64,10 +64,32 @@
     mHas4BitStencil = hasExtension("GL_OES_stencil4");
 
     mExtensions = strdup(buffer);
+
+    const char* version = (const char*) glGetString(GL_VERSION);
+    mVersion = strdup(version);
+
+    // Section 6.1.5 of the OpenGL ES specification indicates the GL version
+    // string strictly follows this format:
+    //
+    // OpenGL<space>ES<space><version number><space><vendor-specific information>
+    //
+    // In addition section 6.1.5 describes the version number thusly:
+    //
+    // "The version number is either of the form major number.minor number or
+    // major number.minor number.release number, where the numbers all have one
+    // or more digits. The release number and vendor specific information are
+    // optional."
+
+    if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) !=2) {
+        // If we cannot parse the version number, assume OpenGL ES 2.0
+        mVersionMajor = 2;
+        mVersionMinor = 0;
+    }
 }
 
 Extensions::~Extensions() {
    free(mExtensions);
+   free(mVersion);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -80,6 +102,7 @@
 }
 
 void Extensions::dump() const {
+   ALOGD("%s", mVersion);
    ALOGD("Supported extensions:\n%s", mExtensions);
 }
 
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index a069a6a..54a3987 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -45,6 +45,9 @@
     inline bool has1BitStencil() const { return mHas1BitStencil; }
     inline bool has4BitStencil() const { return mHas4BitStencil; }
 
+    inline int getMajorGlVersion() const { return mVersionMajor; }
+    inline int getMinorGlVersion() const { return mVersionMinor; }
+
     bool hasExtension(const char* extension) const;
 
     void dump() const;
@@ -55,6 +58,7 @@
     SortedVector<String8> mExtensionList;
 
     char* mExtensions;
+    char* mVersion;
 
     bool mHasNPot;
     bool mHasFramebufferFetch;
@@ -64,6 +68,9 @@
     bool mHasTiledRendering;
     bool mHas1BitStencil;
     bool mHas4BitStencil;
+
+    int mVersionMajor;
+    int mVersionMinor;
 }; // class Extensions
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 77b8df1..44dc731 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -21,13 +21,17 @@
 
 #include <cutils/properties.h>
 
+#include <utils/Functor.h>
 #include <utils/Log.h>
 
-#include "RenderScript.h"
+#include <RenderScript.h>
 
+#include "utils/Blur.h"
 #include "utils/Timing.h"
+
 #include "Caches.h"
 #include "Debug.h"
+#include "Extensions.h"
 #include "FontRenderer.h"
 #include "Rect.h"
 
@@ -53,10 +57,7 @@
     mGammaTable = NULL;
     mInitialized = false;
     mMaxNumberOfQuads = 1024;
-    mCurrentQuadIndex = 0;
-    mLastQuadIndex = 0;
 
-    mTextMesh = NULL;
     mCurrentCacheTexture = NULL;
 
     mLinearFiltering = false;
@@ -112,8 +113,6 @@
         // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
         Caches::getInstance().unbindIndicesBuffer();
         glDeleteBuffers(1, &mIndexBufferID);
-
-        delete[] mTextMesh;
     }
 
     LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
@@ -124,9 +123,7 @@
 }
 
 void FontRenderer::flushAllAndInvalidate() {
-    if (mCurrentQuadIndex != 0) {
-        issueDrawCommand();
-    }
+    issueDrawCommand();
 
     LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
     while (it.next()) {
@@ -234,6 +231,9 @@
         // Large-glyph texture memory is allocated only as needed
         cacheTexture->allocateTexture();
     }
+    if (!cacheTexture->mesh()) {
+        cacheTexture->allocateMesh();
+    }
 
     // Tells us whether the glyphs is B&W (1 bit per pixel)
     // or anti-aliased (8 bits per pixel)
@@ -305,11 +305,12 @@
 }
 
 CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
-    CacheTexture* cacheTexture = new CacheTexture(width, height);
+    CacheTexture* cacheTexture = new CacheTexture(width, height, mMaxNumberOfQuads);
 
     if (allocate) {
         Caches::getInstance().activeTexture(0);
         cacheTexture->allocateTexture();
+        cacheTexture->allocateMesh();
     }
 
     return cacheTexture;
@@ -354,12 +355,6 @@
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
 
     free(indexBufferData);
-
-    uint32_t coordSize = 2;
-    uint32_t uvSize = 2;
-    uint32_t vertsPerQuad = 4;
-    uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
-    mTextMesh = new float[vertexBufferSize];
 }
 
 // We don't want to allocate anything unless we actually draw text
@@ -374,15 +369,6 @@
     mInitialized = true;
 }
 
-void FontRenderer::updateDrawParams() {
-    if (mCurrentQuadIndex != mLastQuadIndex) {
-        mDrawOffsets.add((uint16_t*)(mLastQuadIndex * sizeof(uint16_t) * 6));
-        mDrawCounts.add(mCurrentQuadIndex - mLastQuadIndex);
-        mDrawCacheTextures.add(mCurrentCacheTexture);
-        mLastQuadIndex = mCurrentQuadIndex;
-    }
-}
-
 void FontRenderer::checkTextureUpdate() {
     if (!mUploadTexture) {
         return;
@@ -390,108 +376,118 @@
 
     Caches& caches = Caches::getInstance();
     GLuint lastTextureId = 0;
+
+    // OpenGL ES 3.0+ lets us specify the row length for unpack operations such
+    // as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
+    // With OpenGL ES 2.0 we have to upload entire stripes instead.
+    const bool hasUnpackRowLength = Extensions::getInstance().getMajorGlVersion() >= 3;
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
     // Iterate over all the cache textures and see which ones need to be updated
     for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
         CacheTexture* cacheTexture = mCacheTextures[i];
         if (cacheTexture->isDirty() && cacheTexture->getTexture()) {
-            // Can't copy inner rect; glTexSubimage expects pointer to deal with entire buffer
-            // of data. So expand the dirty rect to the encompassing horizontal stripe.
             const Rect* dirtyRect = cacheTexture->getDirtyRect();
-            uint32_t x = 0;
+            uint32_t x = hasUnpackRowLength ? dirtyRect->left : 0;
             uint32_t y = dirtyRect->top;
             uint32_t width = cacheTexture->getWidth();
             uint32_t height = dirtyRect->getHeight();
-            void* textureData = cacheTexture->getTexture() + y * width;
+            void* textureData = cacheTexture->getTexture() + y * width + x;
 
             if (cacheTexture->getTextureId() != lastTextureId) {
                 lastTextureId = cacheTexture->getTextureId();
                 caches.activeTexture(0);
                 glBindTexture(GL_TEXTURE_2D, lastTextureId);
+
+                // The unpack row length only needs to be specified when a new
+                // texture is bound
+                if (hasUnpackRowLength) {
+                    glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
+                }
             }
+
+            // If we can upload a sub-rectangle, use the dirty rect width
+            // instead of the width of the entire texture
+            if (hasUnpackRowLength) {
+                width = dirtyRect->getWidth();
+            }
+
 #if DEBUG_FONT_RENDERER
             ALOGD("glTexSubimage for cacheTexture %d: x, y, width height = %d, %d, %d, %d",
                     i, x, y, width, height);
 #endif
+
             glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
                     GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
+
             cacheTexture->setDirty(false);
         }
     }
 
+    // Reset to default unpack row length to avoid affecting texture
+    // uploads in other parts of the renderer
+    if (hasUnpackRowLength) {
+        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    }
+
     mUploadTexture = false;
 }
 
 void FontRenderer::issueDrawCommand() {
-    updateDrawParams();
-    checkTextureUpdate();
+    bool first = true;
+    bool force = false;
 
+    GLuint lastId = 0;
     Caches& caches = Caches::getInstance();
-    caches.bindIndicesBuffer(mIndexBufferID);
-    if (!mDrawn) {
-        float* buffer = mTextMesh;
-        int offset = 2;
 
-        bool force = caches.unbindMeshBuffer();
-        caches.bindPositionVertexPointer(force, buffer);
-        caches.bindTexCoordsVertexPointer(force, buffer + offset);
-    }
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        CacheTexture* texture = mCacheTextures[i];
+        if (texture->canDraw()) {
+            if (first) {
+                if (mFunctor) (*mFunctor)(0, NULL);
 
-    for (uint32_t i = 0; i < mDrawOffsets.size(); i++) {
-        uint16_t* offset = mDrawOffsets[i];
-        uint32_t count = mDrawCounts[i];
-        CacheTexture* texture = mDrawCacheTextures[i];
+                checkTextureUpdate();
+                caches.bindIndicesBuffer(mIndexBufferID);
 
-        caches.activeTexture(0);
-        glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
+                if (!mDrawn) {
+                    // If returns true, a VBO was bound and we must
+                    // rebind our vertex attrib pointers even if
+                    // they have the same values as the current pointers
+                    force = caches.unbindMeshBuffer();
+                }
 
-        texture->setLinearFiltering(mLinearFiltering, false);
+                caches.activeTexture(0);
+                first = false;
+            }
 
-        glDrawElements(GL_TRIANGLES, count * 6, GL_UNSIGNED_SHORT, offset);
+            glBindTexture(GL_TEXTURE_2D, texture->getTextureId());
+            texture->setLinearFiltering(mLinearFiltering, false);
+
+            TextureVertex* mesh = texture->mesh();
+            caches.bindPositionVertexPointer(force, &mesh[0].position[0]);
+            caches.bindTexCoordsVertexPointer(force, &mesh[0].texture[0]);
+            force = false;
+
+            glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
+                    GL_UNSIGNED_SHORT, texture->indices());
+
+            texture->resetMesh();
+        }
     }
 
     mDrawn = true;
-
-    mCurrentQuadIndex = 0;
-    mLastQuadIndex = 0;
-    mDrawOffsets.clear();
-    mDrawCounts.clear();
-    mDrawCacheTextures.clear();
 }
 
 void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
         float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
         float x4, float y4, float u4, float v4, CacheTexture* texture) {
     if (texture != mCurrentCacheTexture) {
-        updateDrawParams();
         // Now use the new texture id
         mCurrentCacheTexture = texture;
     }
 
-    const uint32_t vertsPerQuad = 4;
-    const uint32_t floatsPerVert = 4;
-    float* currentPos = mTextMesh + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
-
-    (*currentPos++) = x1;
-    (*currentPos++) = y1;
-    (*currentPos++) = u1;
-    (*currentPos++) = v1;
-
-    (*currentPos++) = x2;
-    (*currentPos++) = y2;
-    (*currentPos++) = u2;
-    (*currentPos++) = v2;
-
-    (*currentPos++) = x3;
-    (*currentPos++) = y3;
-    (*currentPos++) = u3;
-    (*currentPos++) = v3;
-
-    (*currentPos++) = x4;
-    (*currentPos++) = y4;
-    (*currentPos++) = u4;
-    (*currentPos++) = v4;
-
-    mCurrentQuadIndex++;
+    mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
+            x3, y3, u3, v3, x4, y4, u4, v4);
 }
 
 void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
@@ -512,7 +508,7 @@
         mBounds->bottom = fmax(mBounds->bottom, y1);
     }
 
-    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
+    if (mCurrentCacheTexture->endOfMesh()) {
         issueDrawCommand();
     }
 }
@@ -530,7 +526,7 @@
         mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
     }
 
-    if (mCurrentQuadIndex == mMaxNumberOfQuads) {
+    if (mCurrentCacheTexture->endOfMesh()) {
         issueDrawCommand();
     }
 }
@@ -569,7 +565,7 @@
     }
 
     int size = paddedWidth * paddedHeight;
-    uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
+    uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
     memset(dataBuffer, 0, size);
 
     int penX = radius - bounds.left;
@@ -595,11 +591,12 @@
     return image;
 }
 
-void FontRenderer::initRender(const Rect* clip, Rect* bounds) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
     checkInit();
 
     mDrawn = false;
     mBounds = bounds;
+    mFunctor = functor;
     mClip = clip;
 }
 
@@ -607,9 +604,7 @@
     mBounds = NULL;
     mClip = NULL;
 
-    if (mCurrentQuadIndex != 0) {
-        issueDrawCommand();
-    }
+    issueDrawCommand();
 }
 
 void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) {
@@ -619,13 +614,13 @@
 
 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) {
+        const float* positions, Rect* bounds, Functor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
     }
 
-    initRender(clip, bounds);
+    initRender(clip, bounds, functor);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
     finishRender();
 
@@ -640,7 +635,7 @@
         return false;
     }
 
-    initRender(clip, bounds);
+    initRender(clip, bounds, NULL);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
     finishRender();
 
@@ -655,147 +650,21 @@
     }
 }
 
-void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
-    // Compute gaussian weights for the blur
-    // e is the euler's number
-    float e = 2.718281828459045f;
-    float pi = 3.1415926535897932f;
-    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
-    // x is of the form [-radius .. 0 .. radius]
-    // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.3  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.3f * (float) radius + 0.6f;
-
-    // Now compute the coefficints
-    // We will store some redundant values to save some math during
-    // the blur calculations
-    // precompute some values
-    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
-    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
-
-    float normalizeFactor = 0.0f;
-    for (int32_t r = -radius; r <= radius; r ++) {
-        float floatR = (float) r;
-        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
-        normalizeFactor += weights[r + radius];
-    }
-
-    //Now we need to normalize the weights because all our coefficients need to add up to one
-    normalizeFactor = 1.0f / normalizeFactor;
-    for (int32_t r = -radius; r <= radius; r ++) {
-        weights[r + radius] *= normalizeFactor;
-    }
-}
-
-void FontRenderer::horizontalBlur(float* weights, int32_t radius,
-        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
-    float blurredPixel = 0.0f;
-    float currentPixel = 0.0f;
-
-    for (int32_t y = 0; y < height; y ++) {
-
-        const uint8_t* input = source + y * width;
-        uint8_t* output = dest + y * width;
-
-        for (int32_t x = 0; x < width; x ++) {
-            blurredPixel = 0.0f;
-            const float* gPtr = weights;
-            // Optimization for non-border pixels
-            if (x > radius && x < (width - radius)) {
-                const uint8_t *i = input + (x - radius);
-                for (int r = -radius; r <= radius; r ++) {
-                    currentPixel = (float) (*i);
-                    blurredPixel += currentPixel * gPtr[0];
-                    gPtr++;
-                    i++;
-                }
-            } else {
-                for (int32_t r = -radius; r <= radius; r ++) {
-                    // Stepping left and right away from the pixel
-                    int validW = x + r;
-                    if (validW < 0) {
-                        validW = 0;
-                    }
-                    if (validW > width - 1) {
-                        validW = width - 1;
-                    }
-
-                    currentPixel = (float) input[validW];
-                    blurredPixel += currentPixel * gPtr[0];
-                    gPtr++;
-                }
-            }
-            *output = (uint8_t)blurredPixel;
-            output ++;
-        }
-    }
-}
-
-void FontRenderer::verticalBlur(float* weights, int32_t radius,
-        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
-    float blurredPixel = 0.0f;
-    float currentPixel = 0.0f;
-
-    for (int32_t y = 0; y < height; y ++) {
-        uint8_t* output = dest + y * width;
-
-        for (int32_t x = 0; x < width; x ++) {
-            blurredPixel = 0.0f;
-            const float* gPtr = weights;
-            const uint8_t* input = source + x;
-            // Optimization for non-border pixels
-            if (y > radius && y < (height - radius)) {
-                const uint8_t *i = input + ((y - radius) * width);
-                for (int32_t r = -radius; r <= radius; r ++) {
-                    currentPixel = (float)(*i);
-                    blurredPixel += currentPixel * gPtr[0];
-                    gPtr++;
-                    i += width;
-                }
-            } else {
-                for (int32_t r = -radius; r <= radius; r ++) {
-                    int validH = y + r;
-                    // Clamp to zero and width
-                    if (validH < 0) {
-                        validH = 0;
-                    }
-                    if (validH > height - 1) {
-                        validH = height - 1;
-                    }
-
-                    const uint8_t *i = input + validH * width;
-                    currentPixel = (float) (*i);
-                    blurredPixel += currentPixel * gPtr[0];
-                    gPtr++;
-                }
-            }
-            *output = (uint8_t) blurredPixel;
-            output++;
-        }
-    }
-}
-
 void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
     if (width * height * radius < RS_MIN_INPUT_CUTOFF) {
         float *gaussian = new float[2 * radius + 1];
-        computeGaussianWeights(gaussian, radius);
+        Blur::generateGaussianWeights(gaussian, radius);
 
         uint8_t* scratch = new uint8_t[width * height];
-
-        horizontalBlur(gaussian, radius, *image, scratch, width, height);
-        verticalBlur(gaussian, radius, scratch, *image, width, height);
+        Blur::horizontal(gaussian, radius, *image, scratch, width, height);
+        Blur::vertical(gaussian, radius, scratch, *image, width, height);
 
         delete[] gaussian;
         delete[] scratch;
         return;
     }
 
-    uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
+    uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
 
     if (mRs.get() == 0) {
         mRs = new RSC::RS();
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index d0c44ef..1da3b6c 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -28,6 +28,7 @@
 #include "font/CacheTexture.h"
 #include "font/CachedGlyphInfo.h"
 #include "font/Font.h"
+#include "utils/SortedList.h"
 #include "Matrix.h"
 #include "Properties.h"
 
@@ -37,6 +38,8 @@
     class ScriptIntrinsicBlur;
 }
 
+class Functor;
+
 namespace android {
 namespace uirenderer {
 
@@ -61,7 +64,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);
+            uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds,
+            Functor* functor);
     // 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);
@@ -87,13 +91,8 @@
     DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, uint32_t radius, const float* positions);
 
-    GLuint getTexture(bool linearFiltering = false) {
-        checkInit();
-
-        mCurrentCacheTexture->setLinearFiltering(linearFiltering);
+    void setTextureFiltering(bool linearFiltering) {
         mLinearFiltering = linearFiltering;
-
-        return mCurrentCacheTexture->getTextureId();
     }
 
     uint32_t getCacheSize() const {
@@ -124,7 +123,7 @@
     void initVertexArrayBuffers();
 
     void checkInit();
-    void initRender(const Rect* clip, Rect* bounds);
+    void initRender(const Rect* clip, Rect* bounds, Functor* functor);
     void finishRender();
 
     void issueDrawCommand();
@@ -143,7 +142,6 @@
 
     void removeFont(const Font* font);
 
-    void updateDrawParams();
     void checkTextureUpdate();
 
     void setTextureDirty() {
@@ -164,14 +162,10 @@
 
     bool mUploadTexture;
 
-    // Pointer to vertex data to speed up frame to frame work
-    float* mTextMesh;
-    uint32_t mCurrentQuadIndex;
-    uint32_t mLastQuadIndex;
     uint32_t mMaxNumberOfQuads;
-
     uint32_t mIndexBufferID;
 
+    Functor* mFunctor;
     const Rect* mClip;
     Rect* mBounds;
     bool mDrawn;
@@ -180,10 +174,6 @@
 
     bool mLinearFiltering;
 
-    Vector<uint16_t*> mDrawOffsets;
-    Vector<uint32_t> mDrawCounts;
-    Vector<CacheTexture*> mDrawCacheTextures;
-
     // RS constructs
     sp<RSC::RS> mRs;
     sp<const RSC::Element> mRsElement;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 78f9cf5..eef366c 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "OpenGLRenderer"
 
 #include <utils/JenkinsHash.h>
-#include <utils/threads.h>
 
 #include "Caches.h"
 #include "Debug.h"
@@ -28,13 +27,6 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-#define GRADIENT_TEXTURE_HEIGHT 2
-#define GRADIENT_BYTES_PER_PIXEL 4
-
-///////////////////////////////////////////////////////////////////////////////
 // Functions
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -84,6 +76,10 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
 
     mCache.setOnEntryRemovedListener(this);
+
+    const Extensions& extensions = Extensions::getInstance();
+    mUseFloatTexture = extensions.getMajorGlVersion() >= 3;
+    mHasNpot = extensions.hasNPot();
 }
 
 GradientCache::GradientCache(uint32_t maxByteSize):
@@ -121,7 +117,7 @@
 
 void GradientCache::operator()(GradientCacheEntry& shader, Texture*& texture) {
     if (texture) {
-        const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
+        const uint32_t size = texture->width * texture->height * bytesPerPixel();
         mSize -= size;
 
         glDeleteTextures(1, &texture->id);
@@ -152,7 +148,7 @@
         GradientInfo& info) {
     uint32_t width = 256 * (count - 1);
 
-    if (!Extensions::getInstance().hasNPot()) {
+    if (!mHasNpot) {
         width = 1 << (31 - __builtin_clz(width));
     }
 
@@ -176,12 +172,12 @@
 
     Texture* texture = new Texture;
     texture->width = info.width;
-    texture->height = GRADIENT_TEXTURE_HEIGHT;
+    texture->height = 2;
     texture->blend = info.hasAlpha;
     texture->generation = 1;
 
     // Asume the cache is always big enough
-    const uint32_t size = texture->width * texture->height * GRADIENT_BYTES_PER_PIXEL;
+    const uint32_t size = texture->width * texture->height * bytesPerPixel();
     while (getSize() + size > mMaxSize) {
         mCache.removeOldest();
     }
@@ -194,69 +190,110 @@
     return texture;
 }
 
+size_t GradientCache::bytesPerPixel() const {
+    // We use 4 channels (RGBA)
+    return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
+}
+
+void GradientCache::splitToBytes(uint32_t inColor, GradientColor& outColor) const {
+    outColor.r = (inColor >> 16) & 0xff;
+    outColor.g = (inColor >>  8) & 0xff;
+    outColor.b = (inColor >>  0) & 0xff;
+    outColor.a = (inColor >> 24) & 0xff;
+}
+
+void GradientCache::splitToFloats(uint32_t inColor, GradientColor& outColor) const {
+    outColor.r = ((inColor >> 16) & 0xff) / 255.0f;
+    outColor.g = ((inColor >>  8) & 0xff) / 255.0f;
+    outColor.b = ((inColor >>  0) & 0xff) / 255.0f;
+    outColor.a = ((inColor >> 24) & 0xff) / 255.0f;
+}
+
+void GradientCache::mixBytes(GradientColor& start, GradientColor& end, float amount,
+        uint8_t*& dst) const {
+    float oppAmount = 1.0f - amount;
+    const float alpha = start.a * oppAmount + end.a * amount;
+    const float a = alpha / 255.0f;
+
+    *dst++ = uint8_t(a * (start.r * oppAmount + end.r * amount));
+    *dst++ = uint8_t(a * (start.g * oppAmount + end.g * amount));
+    *dst++ = uint8_t(a * (start.b * oppAmount + end.b * amount));
+    *dst++ = uint8_t(alpha);
+}
+
+void GradientCache::mixFloats(GradientColor& start, GradientColor& end, float amount,
+        uint8_t*& dst) const {
+    float oppAmount = 1.0f - amount;
+    const float a = start.a * oppAmount + end.a * amount;
+
+    float* d = (float*) dst;
+    *d++ = a * (start.r * oppAmount + end.r * amount);
+    *d++ = a * (start.g * oppAmount + end.g * amount);
+    *d++ = a * (start.b * oppAmount + end.b * amount);
+    *d++ = a;
+
+    dst += 4 * sizeof(float);
+}
+
 void GradientCache::generateTexture(uint32_t* colors, float* positions,
         int count, Texture* texture) {
-
     const uint32_t width = texture->width;
-    const GLsizei rowBytes = width * GRADIENT_BYTES_PER_PIXEL;
-    uint32_t pixels[width * texture->height];
+    const GLsizei rowBytes = width * bytesPerPixel();
+    uint8_t pixels[rowBytes * texture->height];
+
+    static ChannelSplitter gSplitters[] = {
+            &android::uirenderer::GradientCache::splitToBytes,
+            &android::uirenderer::GradientCache::splitToFloats,
+    };
+    ChannelSplitter split = gSplitters[mUseFloatTexture];
+
+    static ChannelMixer gMixers[] = {
+            &android::uirenderer::GradientCache::mixBytes,
+            &android::uirenderer::GradientCache::mixFloats,
+    };
+    ChannelMixer mix = gMixers[mUseFloatTexture];
+
+    GradientColor start;
+    (this->*split)(colors[0], start);
+
+    GradientColor end;
+    (this->*split)(colors[1], end);
 
     int currentPos = 1;
+    float startPos = positions[0];
+    float distance = positions[1] - startPos;
 
-    float startA = (colors[0] >> 24) & 0xff;
-    float startR = (colors[0] >> 16) & 0xff;
-    float startG = (colors[0] >>  8) & 0xff;
-    float startB = (colors[0] >>  0) & 0xff;
-
-    float endA = (colors[1] >> 24) & 0xff;
-    float endR = (colors[1] >> 16) & 0xff;
-    float endG = (colors[1] >>  8) & 0xff;
-    float endB = (colors[1] >>  0) & 0xff;
-
-    float start = positions[0];
-    float distance = positions[1] - start;
-
-    uint8_t* p = (uint8_t*) pixels;
+    uint8_t* dst = pixels;
     for (uint32_t x = 0; x < width; x++) {
         float pos = x / float(width - 1);
         if (pos > positions[currentPos]) {
-            startA = endA;
-            startR = endR;
-            startG = endG;
-            startB = endB;
-            start = positions[currentPos];
+            start = end;
+            startPos = positions[currentPos];
 
             currentPos++;
 
-            endA = (colors[currentPos] >> 24) & 0xff;
-            endR = (colors[currentPos] >> 16) & 0xff;
-            endG = (colors[currentPos] >>  8) & 0xff;
-            endB = (colors[currentPos] >>  0) & 0xff;
-            distance = positions[currentPos] - start;
+            (this->*split)(colors[currentPos], end);
+            distance = positions[currentPos] - startPos;
         }
 
-        float amount = (pos - start) / distance;
-        float oppAmount = 1.0f - amount;
-
-        const float alpha = startA * oppAmount + endA * amount;
-        const float a = alpha / 255.0f;
-        *p++ = uint8_t(a * (startR * oppAmount + endR * amount));
-        *p++ = uint8_t(a * (startG * oppAmount + endG * amount));
-        *p++ = uint8_t(a * (startB * oppAmount + endB * amount));
-        *p++ = uint8_t(alpha);
+        float amount = (pos - startPos) / distance;
+        (this->*mix)(start, end, amount, dst);
     }
 
-    for (int i = 1; i < GRADIENT_TEXTURE_HEIGHT; i++) {
-        memcpy(pixels + width * i, pixels, rowBytes);
-    }
+    memcpy(pixels + rowBytes, pixels, rowBytes);
 
     glGenTextures(1, &texture->id);
-
     glBindTexture(GL_TEXTURE_2D, texture->id);
-    glPixelStorei(GL_UNPACK_ALIGNMENT, GRADIENT_BYTES_PER_PIXEL);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
-            GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    if (mUseFloatTexture) {
+        // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, texture->height, 0,
+                GL_RGBA, GL_FLOAT, pixels);
+    } else {
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+    }
 
     texture->setFilter(GL_LINEAR);
     texture->setWrap(GL_CLAMP_TO_EDGE);
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 7dc5b8a..43934d9 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_HWUI_GRADIENT_CACHE_H
 #define ANDROID_HWUI_GRADIENT_CACHE_H
 
-#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
 
 #include <SkShader.h>
 
@@ -160,12 +160,35 @@
 
     void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info);
 
+    size_t bytesPerPixel() const;
+
+    struct GradientColor {
+        float r;
+        float g;
+        float b;
+        float a;
+    };
+
+    typedef void (GradientCache::*ChannelSplitter)(uint32_t inColor,
+            GradientColor& outColor) const;
+
+    void splitToBytes(uint32_t inColor, GradientColor& outColor) const;
+    void splitToFloats(uint32_t inColor, GradientColor& outColor) const;
+
+    typedef void (GradientCache::*ChannelMixer)(GradientColor& start, GradientColor& end,
+            float amount, uint8_t*& dst) const;
+
+    void mixBytes(GradientColor& start, GradientColor& end, float amount, uint8_t*& dst) const;
+    void mixFloats(GradientColor& start, GradientColor& end, float amount, uint8_t*& dst) const;
+
     LruCache<GradientCacheEntry, Texture*> mCache;
 
     uint32_t mSize;
     uint32_t mMaxSize;
 
     GLint mMaxTextureSize;
+    bool mUseFloatTexture;
+    bool mHasNpot;
 
     Vector<SkShader*> mGarbage;
     mutable Mutex mLock;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 1899002..a718294 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,6 +18,8 @@
 
 #include <utils/Log.h>
 
+#include "DisplayList.h"
+#include "DeferredDisplayList.h"
 #include "Layer.h"
 #include "LayerRenderer.h"
 #include "OpenGLRenderer.h"
@@ -43,15 +45,18 @@
     fbo = 0;
     stencil = NULL;
     debugDrawUpdate = false;
+    deferredList = NULL;
     Caches::getInstance().resourceCache.incrementRefcount(this);
 }
 
 Layer::~Layer() {
-    if (mesh) delete mesh;
-    if (meshIndices) delete meshIndices;
     if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
     removeFbo();
     deleteTexture();
+
+    delete[] mesh;
+    delete[] meshIndices;
+    delete deferredList;
 }
 
 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
@@ -70,6 +75,13 @@
         return true;
     }
 
+    const uint32_t maxTextureSize = Caches::getInstance().maxTextureSize;
+    if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
+        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
+                desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
+        return false;
+    }
+
     uint32_t oldWidth = getWidth();
     uint32_t oldHeight = getHeight();
 
@@ -78,7 +90,7 @@
     if (fbo) {
         Caches::getInstance().activeTexture(0);
         bindTexture();
-        allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
+        allocateTexture();
 
         if (glGetError() != GL_NO_ERROR) {
             setSize(oldWidth, oldHeight);
@@ -133,5 +145,61 @@
     }
 }
 
+void Layer::defer() {
+    if (!deferredList) {
+        deferredList = new DeferredDisplayList;
+    }
+    DeferStateStruct deferredState(*deferredList, *renderer,
+            DisplayList::kReplayFlag_ClipChildren);
+
+    const float width = layer.getWidth();
+    const float height = layer.getHeight();
+
+    if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
+            dirtyRect.right >= width && dirtyRect.bottom >= height)) {
+        dirtyRect.set(0, 0, width, height);
+    }
+
+    renderer->initViewport(width, height);
+    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
+            dirtyRect.right, dirtyRect.bottom, !isBlend());
+
+    displayList->defer(deferredState, 0);
+
+    deferredUpdateScheduled = false;
+}
+
+void Layer::flush() {
+    if (deferredList) {
+        renderer->setViewport(layer.getWidth(), layer.getHeight());
+        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
+                !isBlend());
+
+        deferredList->flush(*renderer, dirtyRect);
+
+        renderer->finish();
+        renderer = NULL;
+
+        dirtyRect.setEmpty();
+        displayList = NULL;
+    }
+}
+
+void Layer::render() {
+    renderer->setViewport(layer.getWidth(), layer.getHeight());
+    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
+            !isBlend());
+
+    renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);
+
+    renderer->finish();
+    renderer = NULL;
+
+    dirtyRect.setEmpty();
+
+    deferredUpdateScheduled = false;
+    displayList = NULL;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index ccf1da5..715dfa4 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -42,6 +42,8 @@
 // Forward declarations
 class OpenGLRenderer;
 class DisplayList;
+class DeferredDisplayList;
+class DeferStateStruct;
 
 /**
  * A layer has dimensions and is backed by an OpenGL texture or FBO.
@@ -253,13 +255,14 @@
         texture.id = 0;
     }
 
-    inline void allocateTexture(GLenum format, GLenum storage) {
+    inline void allocateTexture() {
 #if DEBUG_LAYERS
         ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
 #endif
         if (texture.id) {
-            glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0,
-                    format, storage, NULL);
+            glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+            glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
+                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
         }
     }
 
@@ -271,6 +274,10 @@
         return transform;
     }
 
+    void defer();
+    void flush();
+    void render();
+
     /**
      * Bounds of the layer.
      */
@@ -379,6 +386,12 @@
      */
     mat4 transform;
 
+    /**
+     * Used to defer display lists when the layer is updated with a
+     * display list.
+     */
+    DeferredDisplayList* deferredList;
+
 }; // struct Layer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 9aa9615..3e55fff 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -129,8 +129,8 @@
 void LayerRenderer::generateMesh() {
     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
         if (mLayer->mesh) {
-            delete mLayer->mesh;
-            delete mLayer->meshIndices;
+            delete[] mLayer->mesh;
+            delete[] mLayer->meshIndices;
 
             mLayer->mesh = NULL;
             mLayer->meshIndices = NULL;
@@ -153,8 +153,8 @@
     GLsizei elementCount = count * 6;
 
     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
-        delete mLayer->mesh;
-        delete mLayer->meshIndices;
+        delete[] mLayer->mesh;
+        delete[] mLayer->meshIndices;
 
         mLayer->mesh = NULL;
         mLayer->meshIndices = NULL;
@@ -222,6 +222,21 @@
         return NULL;
     }
 
+    // We first obtain a layer before comparing against the max texture size
+    // because layers are not allocated at the exact desired size. They are
+    // always created slighly larger to improve recycling
+    const uint32_t maxTextureSize = caches.maxTextureSize;
+    if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) {
+        ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
+                width, height, maxTextureSize, maxTextureSize);
+
+        // Creating a new layer always increment its refcount by 1, this allows
+        // us to destroy the layer object if one was created for us
+        Caches::getInstance().resourceCache.decrementRefcount(layer);
+
+        return NULL;
+    }
+
     layer->setFbo(fbo);
     layer->layer.set(0.0f, 0.0f, width, height);
     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
@@ -241,16 +256,13 @@
     // Initialize the texture if needed
     if (layer->isEmpty()) {
         layer->setEmpty(false);
-        layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
+        layer->allocateTexture();
 
+        // This should only happen if we run out of memory
         if (glGetError() != GL_NO_ERROR) {
-            ALOGD("Could not allocate texture for layer (fbo=%d %dx%d)",
-                    fbo, width, height);
-
+            ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
             glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-
-            Caches::getInstance().resourceCache.decrementRefcount(layer);
-
+            caches.resourceCache.decrementRefcount(layer);
             return NULL;
         }
     }
@@ -272,7 +284,6 @@
             layer->texCoords.set(0.0f, height / float(layer->getHeight()),
                     width / float(layer->getWidth()), 0.0f);
         } else {
-            Caches::getInstance().resourceCache.decrementRefcount(layer);
             return false;
         }
     }
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 7b7357e..75e280c 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -93,6 +93,14 @@
         return *this;
     }
 
+    friend bool operator==(const Matrix4& a, const Matrix4& b) {
+        return !memcmp(&a.data[0], &b.data[0], 16 * sizeof(float));
+    }
+
+    friend bool operator!=(const Matrix4& a, const Matrix4& b) {
+        return !(a == b);
+    }
+
     void loadIdentity();
 
     void load(const float* v);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 22ec93b..e18d922 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -114,12 +114,14 @@
         mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) {
     mDrawModifiers.mShader = NULL;
     mDrawModifiers.mColorFilter = NULL;
+    mDrawModifiers.mOverrideLayerAlpha = 1.0f;
     mDrawModifiers.mHasShadow = false;
     mDrawModifiers.mHasDrawFilter = false;
 
     memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
 
     mFirstSnapshot = new Snapshot;
+    mFrameStarted = false;
 
     mScissorOptimizationDisabled = false;
 }
@@ -179,39 +181,63 @@
     mFirstSnapshot->viewport.set(0, 0, width, height);
 }
 
-status_t OpenGLRenderer::prepare(bool opaque) {
-    return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
-}
-
-status_t OpenGLRenderer::prepareDirty(float left, float top,
+void OpenGLRenderer::setupFrameState(float left, float top,
         float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
 
+    mOpaque = opaque;
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSnapshot->fbo = getTargetFbo();
     mSaveCount = 1;
 
     mSnapshot->setClip(left, top, right, bottom);
+    mTilingClip.set(left, top, right, bottom);
+}
+
+status_t OpenGLRenderer::startFrame() {
+    if (mFrameStarted) return DrawGlInfo::kStatusDone;
+    mFrameStarted = true;
+
     mDirtyClip = true;
 
-    updateLayers();
+    discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
 
-    discardFramebuffer(left, top, right, bottom);
-
-    syncState();
+    glViewport(0, 0, mWidth, mHeight);
 
     // Functors break the tiling extension in pretty spectacular ways
     // This ensures we don't use tiling when a functor is going to be
     // invoked during the frame
     mSuppressTiling = mCaches.hasRegisteredFunctors();
 
-    mTilingSnapshot = mSnapshot;
-    startTiling(mTilingSnapshot, true);
+    startTiling(mSnapshot, true);
 
     debugOverdraw(true, true);
 
-    return clear(left, top, right, bottom, opaque);
+    return clear(mTilingClip.left, mTilingClip.top,
+            mTilingClip.right, mTilingClip.bottom, mOpaque);
+}
+
+status_t OpenGLRenderer::prepare(bool opaque) {
+    return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
+}
+
+status_t OpenGLRenderer::prepareDirty(float left, float top,
+        float right, float bottom, bool opaque) {
+    setupFrameState(left, top, right, bottom, opaque);
+
+    // Layer renderers will start the frame immediately
+    // The framebuffer renderer will first defer the display list
+    // for each layer and wait until the first drawing command
+    // to start the frame
+    if (mSnapshot->fbo == 0) {
+        syncState();
+        updateLayers();
+    } else {
+        return startFrame();
+    }
+
+    return DrawGlInfo::kStatusDone;
 }
 
 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
@@ -241,8 +267,6 @@
 }
 
 void OpenGLRenderer::syncState() {
-    glViewport(0, 0, mWidth, mHeight);
-
     if (mCaches.blend) {
         glEnable(GL_BLEND);
     } else {
@@ -252,9 +276,9 @@
 
 void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
     if (!mSuppressTiling) {
-        Rect* clip = mTilingSnapshot->clipRect;
+        Rect* clip = &mTilingClip;
         if (s->flags & Snapshot::kFlagFboTarget) {
-            clip = &s->layer->clipRect;
+            clip = &(s->layer->clipRect);
         }
 
         startTiling(*clip, s->height, opaque);
@@ -276,6 +300,12 @@
     renderOverdraw();
     endTiling();
 
+    // When finish() is invoked on FBO 0 we've reached the end
+    // of the current frame
+    if (getTargetFbo() == 0) {
+        mCaches.pathCache.trim();
+    }
+
     if (!suppressErrorChecks()) {
 #if DEBUG_OPENGL
         GLenum status = GL_NO_ERROR;
@@ -306,6 +336,8 @@
         }
 #endif
     }
+
+    mFrameStarted = false;
 }
 
 void OpenGLRenderer::interrupt() {
@@ -400,6 +432,8 @@
 }
 
 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
+    if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
+
     interrupt();
     detachFunctor(functor);
 
@@ -474,10 +508,10 @@
 
 void OpenGLRenderer::renderOverdraw() {
     if (mCaches.debugOverdraw && getTargetFbo() == 0) {
-        const Rect* clip = mTilingSnapshot->clipRect;
+        const Rect* clip = &mTilingClip;
 
         mCaches.enableScissor();
-        mCaches.setScissor(clip->left, mTilingSnapshot->height - clip->bottom,
+        mCaches.setScissor(clip->left, mFirstSnapshot->height - clip->bottom,
                 clip->right - clip->left, clip->bottom - clip->top);
 
         mCaches.stencil.enableDebugTest(2);
@@ -497,8 +531,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
-    if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
-        OpenGLRenderer* renderer = layer->renderer;
+    if (layer->deferredUpdateScheduled && layer->renderer &&
+            layer->displayList && layer->displayList->isRenderable()) {
         Rect& dirty = layer->dirtyRect;
 
         if (inFrame) {
@@ -506,20 +540,17 @@
             debugOverdraw(false, false);
         }
 
-        renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
-        renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
-        renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren);
-        renderer->finish();
+        if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
+            layer->render();
+        } else {
+            layer->defer();
+        }
 
         if (inFrame) {
             resumeAfterLayer();
             startTiling(mSnapshot);
         }
 
-        dirty.setEmpty();
-        layer->deferredUpdateScheduled = false;
-        layer->renderer = NULL;
-        layer->displayList = NULL;
         layer->debugDrawUpdate = mCaches.debugLayersUpdates;
 
         return true;
@@ -529,25 +560,70 @@
 }
 
 void OpenGLRenderer::updateLayers() {
+    // If draw deferring is enabled this method will simply defer
+    // the display list of each individual layer. The layers remain
+    // in the layer updates list which will be cleared by flushLayers().
     int count = mLayerUpdates.size();
     if (count > 0) {
-        startMark("Layer Updates");
+        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+            startMark("Layer Updates");
+        } else {
+            startMark("Defer Layer Updates");
+        }
 
-        // Note: it is very important to update the layers in reverse order
-        for (int i = count - 1; i >= 0; i--) {
+        // Note: it is very important to update the layers in order
+        for (int i = 0; i < count; i++) {
             Layer* layer = mLayerUpdates.itemAt(i);
             updateLayer(layer, false);
-            mCaches.resourceCache.decrementRefcount(layer);
+            if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+                mCaches.resourceCache.decrementRefcount(layer);
+            }
         }
-        mLayerUpdates.clear();
 
+        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
+            mLayerUpdates.clear();
+            glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
+        }
+        endMark();
+    }
+}
+
+void OpenGLRenderer::flushLayers() {
+    int count = mLayerUpdates.size();
+    if (count > 0) {
+        startMark("Apply Layer Updates");
+        char layerName[12];
+
+        // Note: it is very important to update the layers in order
+        for (int i = 0; i < count; i++) {
+            sprintf(layerName, "Layer #%d", i);
+            startMark(layerName);
+
+            Layer* layer = mLayerUpdates.itemAt(i);
+            layer->flush();
+            mCaches.resourceCache.decrementRefcount(layer);
+
+            endMark();
+        }
+
+        mLayerUpdates.clear();
         glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo());
+
         endMark();
     }
 }
 
 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
     if (layer) {
+        // Make sure we don't introduce duplicates.
+        // SortedVector would do this automatically but we need to respect
+        // the insertion order. The linear search is not an issue since
+        // this list is usually very short (typically one item, at most a few)
+        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
+            if (mLayerUpdates.itemAt(i) == layer) {
+                return;
+            }
+        }
         mLayerUpdates.push_back(layer);
         mCaches.resourceCache.incrementRefcount(layer);
     }
@@ -618,7 +694,10 @@
     }
 
     if (restoreLayer) {
+        endMark(); // Savelayer
+        startMark("ComposeLayer");
         composeLayer(current, previous);
+        endMark();
     }
 
     return restoreClip;
@@ -629,38 +708,86 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
-        SkPaint* p, int flags) {
+        int alpha, SkXfermode::Mode mode, int flags) {
     const GLuint previousFbo = mSnapshot->fbo;
     const int count = saveSnapshot(flags);
 
     if (!mSnapshot->isIgnored()) {
-        int alpha = 255;
-        SkXfermode::Mode mode;
-
-        if (p) {
-            alpha = p->getAlpha();
-            mode = getXfermode(p->getXfermode());
-        } else {
-            mode = SkXfermode::kSrcOver_Mode;
-        }
-
         createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo);
     }
 
     return count;
 }
 
-int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
-        int alpha, int flags) {
-    if (alpha >= 255) {
-        return saveLayer(left, top, right, bottom, NULL, flags);
+void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
+    const Rect untransformedBounds(bounds);
+
+    currentTransform().mapRect(bounds);
+
+    // Layers only make sense if they are in the framebuffer's bounds
+    if (bounds.intersect(*mSnapshot->clipRect)) {
+        // We cannot work with sub-pixels in this case
+        bounds.snapToPixelBoundaries();
+
+        // When the layer is not an FBO, we may use glCopyTexImage so we
+        // need to make sure the layer does not extend outside the bounds
+        // of the framebuffer
+        if (!bounds.intersect(mSnapshot->previous->viewport)) {
+            bounds.setEmpty();
+        } else if (fboLayer) {
+            clip.set(bounds);
+            mat4 inverse;
+            inverse.loadInverse(currentTransform());
+            inverse.mapRect(clip);
+            clip.snapToPixelBoundaries();
+            if (clip.intersect(untransformedBounds)) {
+                clip.translate(-untransformedBounds.left, -untransformedBounds.top);
+                bounds.set(untransformedBounds);
+            } else {
+                clip.setEmpty();
+            }
+        }
     } else {
-        SkPaint paint;
-        paint.setAlpha(alpha);
-        return saveLayer(left, top, right, bottom, &paint, flags);
+        bounds.setEmpty();
     }
 }
 
+void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
+        bool fboLayer, int alpha) {
+    if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
+            bounds.getHeight() > mCaches.maxTextureSize ||
+            (fboLayer && clip.isEmpty())) {
+        mSnapshot->empty = fboLayer;
+    } else {
+        mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
+    }
+}
+
+int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
+        int alpha, SkXfermode::Mode mode, int flags) {
+    const GLuint previousFbo = mSnapshot->fbo;
+    const int count = saveSnapshot(flags);
+
+    if (!mSnapshot->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
+        // initialize the snapshot as though it almost represents an FBO layer so deferred draw
+        // operations will be able to store and restore the current clip and transform info, and
+        // quick rejection will be correct (for display lists)
+
+        Rect bounds(left, top, right, bottom);
+        Rect clip;
+        calculateLayerBoundsAndClip(bounds, clip, true);
+        updateSnapshotIgnoreForLayer(bounds, clip, true, alpha);
+
+        if (!mSnapshot->isIgnored()) {
+            mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
+            mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+        }
+    }
+
+    return count;
+}
+
+
 /**
  * Layers are viewed by Skia are slightly different than layers in image editing
  * programs (for instance.) When a layer is created, previously created layers
@@ -722,46 +849,11 @@
     // Window coordinates of the layer
     Rect clip;
     Rect bounds(left, top, right, bottom);
-    Rect untransformedBounds(bounds);
-    currentTransform().mapRect(bounds);
-
-    // Layers only make sense if they are in the framebuffer's bounds
-    if (bounds.intersect(*mSnapshot->clipRect)) {
-        // We cannot work with sub-pixels in this case
-        bounds.snapToPixelBoundaries();
-
-        // When the layer is not an FBO, we may use glCopyTexImage so we
-        // need to make sure the layer does not extend outside the bounds
-        // of the framebuffer
-        if (!bounds.intersect(mSnapshot->previous->viewport)) {
-            bounds.setEmpty();
-        } else if (fboLayer) {
-            clip.set(bounds);
-            mat4 inverse;
-            inverse.loadInverse(currentTransform());
-            inverse.mapRect(clip);
-            clip.snapToPixelBoundaries();
-            if (clip.intersect(untransformedBounds)) {
-                clip.translate(-left, -top);
-                bounds.set(untransformedBounds);
-            } else {
-                clip.setEmpty();
-            }
-        }
-    } else {
-        bounds.setEmpty();
-    }
-
-    if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
-            bounds.getHeight() > mCaches.maxTextureSize ||
-            (fboLayer && clip.isEmpty())) {
-        mSnapshot->empty = fboLayer;
-    } else {
-        mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
-    }
+    calculateLayerBoundsAndClip(bounds, clip, fboLayer);
+    updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha);
 
     // Bail out if we won't draw in this snapshot
-    if (mSnapshot->invisible || mSnapshot->empty) {
+    if (mSnapshot->isIgnored()) {
         return false;
     }
 
@@ -783,6 +875,7 @@
     mSnapshot->flags |= Snapshot::kFlagIsLayer;
     mSnapshot->layer = layer;
 
+    startMark("SaveLayer");
     if (fboLayer) {
         return createFboLayer(layer, bounds, clip, previousFbo);
     } else {
@@ -829,7 +922,7 @@
 
     // Initialize the texture if needed
     if (layer->isEmpty()) {
-        layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
+        layer->allocateTexture();
         layer->setEmpty(false);
     }
 
@@ -918,7 +1011,7 @@
 }
 
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
-    float alpha = layer->getAlpha() / 255.0f;
+    float alpha = layer->getAlpha() / 255.0f * mSnapshot->alpha;
 
     setupDraw();
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
@@ -982,9 +1075,10 @@
             layer->setFilter(GL_LINEAR, true);
         }
 
+        float alpha = getLayerAlpha(layer);
+        bool blend = layer->isBlend() || alpha < 1.0f;
         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
-                layer->getTexture(), layer->getAlpha() / 255.0f,
-                layer->getMode(), layer->isBlend(),
+                layer->getTexture(), alpha, layer->getMode(), blend,
                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
                 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
 
@@ -1019,7 +1113,7 @@
             rects = safeRegion.getArray(&count);
         }
 
-        const float alpha = layer->getAlpha() / 255.0f;
+        const float alpha = getLayerAlpha(layer);
         const float texX = 1.0f / float(layer->getWidth());
         const float texY = 1.0f / float(layer->getHeight());
         const float height = rect.getHeight();
@@ -1219,36 +1313,46 @@
 // State Deferral
 ///////////////////////////////////////////////////////////////////////////////
 
-bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state) {
+bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
     const Rect& currentClip = *(mSnapshot->clipRect);
     const mat4& currentMatrix = *(mSnapshot->transform);
 
-    // state only has bounds initialized in local coordinates
-    if (!state.mBounds.isEmpty()) {
-        currentMatrix.mapRect(state.mBounds);
-        if (!state.mBounds.intersect(currentClip)) {
-            // quick rejected
-            return true;
+    if (stateDeferFlags & kStateDeferFlag_Draw) {
+        // state has bounds initialized in local coordinates
+        if (!state.mBounds.isEmpty()) {
+            currentMatrix.mapRect(state.mBounds);
+            if (!state.mBounds.intersect(currentClip)) {
+                // quick rejected
+                return true;
+            }
+        } else {
+            state.mBounds.set(currentClip);
         }
-    } else {
-        state.mBounds.set(currentClip);
     }
 
-    state.mClip.set(currentClip);
+    if (stateDeferFlags & kStateDeferFlag_Clip) {
+        state.mClip.set(currentClip);
+    } else {
+        state.mClip.setEmpty();
+    }
+
+    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
+    // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
     state.mMatrix.load(currentMatrix);
     state.mDrawModifiers = mDrawModifiers;
+    state.mAlpha = mSnapshot->alpha;
     return false;
 }
 
 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state) {
     currentTransform().load(state.mMatrix);
-
-    // NOTE: a clip RECT will be saved and restored, but DeferredDisplayState doesn't support
-    // complex clips. In the future, we should add support for deferral of operations clipped by
-    // these. for now, we don't defer with complex clips (see OpenGLRenderer::disallowDeferral())
-    mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
-    dirtyClip();
     mDrawModifiers = state.mDrawModifiers;
+    mSnapshot->alpha = state.mAlpha;
+
+    if (!state.mClip.isEmpty()) {
+        mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom);
+        dirtyClip();
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1725,7 +1829,7 @@
 }
 
 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
-    bindTexture(texture);
+    if (texture) bindTexture(texture);
     mTextureUnit++;
     mCaches.enableTexCoordsVertexArray();
 }
@@ -1799,16 +1903,27 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags) {
+status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
+        int32_t replayFlags) {
+    status_t status;
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList && displayList->isRenderable()) {
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
-            return displayList->replay(*this, dirty, flags, 0);
+            status = startFrame();
+            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
+            displayList->replay(replayStruct, 0);
+            return status | replayStruct.mDrawGlStatus;
         }
 
         DeferredDisplayList deferredList;
-        return displayList->replay(*this, dirty, flags, 0, &deferredList);
+        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
+        displayList->defer(deferStruct, 0);
+
+        flushLayers();
+        status = startFrame();
+
+        return status | deferredList.flush(*this, dirty);
     }
 
     return DrawGlInfo::kStatusDone;
@@ -2124,7 +2239,7 @@
         float left, float top, float right, float bottom, SkPaint* paint) {
     int alpha;
     SkXfermode::Mode mode;
-    getAlphaAndModeDirect(paint, &alpha, &mode);
+    getAlphaAndMode(paint, &alpha, &mode);
 
     return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
             left, top, right, bottom, alpha, mode);
@@ -2251,9 +2366,11 @@
     // TODO: try clipping large paths to viewport
     PathTessellator::tessellatePath(path, paint, mSnapshot->transform, vertexBuffer);
 
-    SkRect bounds = path.getBounds();
-    PathTessellator::expandBoundsForStroke(bounds, paint, false);
-    dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
+    if (hasLayer()) {
+        SkRect bounds = path.getBounds();
+        PathTessellator::expandBoundsForStroke(bounds, paint, false);
+        dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform());
+    }
 
     return drawVertexBuffer(vertexBuffer, paint);
 }
@@ -2377,13 +2494,14 @@
 
 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
     if (p->getPathEffect() != 0) {
         mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
+        const PathTexture* texture = mCaches.pathCache.getRoundRect(
                 right - left, bottom - top, rx, ry, p);
         return drawShape(left, top, texture, p);
     }
@@ -2402,12 +2520,13 @@
 
 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) {
     if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius,
-            x + radius, y + radius, p)) {
+            x + radius, y + radius, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
     if (p->getPathEffect() != 0) {
         mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, p);
+        const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
         return drawShape(x - radius, y - radius, texture, p);
     }
 
@@ -2422,13 +2541,14 @@
 
 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
         SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
     if (p->getPathEffect() != 0) {
         mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, p);
+        const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
         return drawShape(left, top, texture, p);
     }
 
@@ -2443,7 +2563,8 @@
 
 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2454,7 +2575,7 @@
     // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
     if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
         mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
+        const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
                 startAngle, sweepAngle, useCenter, p);
         return drawShape(left, top, texture, p);
     }
@@ -2479,7 +2600,8 @@
 #define SkPaintDefaults_MiterLimit SkIntToScalar(4)
 
 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2489,7 +2611,7 @@
                 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
             mCaches.activeTexture(0);
             const PathTexture* texture =
-                    mCaches.rectShapeCache.getRect(right - left, bottom - top, p);
+                    mCaches.pathCache.getRect(right - left, bottom - top, p);
             return drawShape(left, top, texture, p);
         }
 
@@ -2555,6 +2677,48 @@
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
+class TextSetupFunctor: public Functor {
+public:
+    TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate,
+            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
+            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
+            alpha(alpha), mode(mode), paint(paint) {
+    }
+    ~TextSetupFunctor() { }
+
+    status_t operator ()(int what, void* data) {
+        renderer.setupDraw();
+        renderer.setupDrawTextGamma(paint);
+        renderer.setupDrawDirtyRegionsDisabled();
+        renderer.setupDrawWithTexture(true);
+        renderer.setupDrawAlpha8Color(paint->getColor(), alpha);
+        renderer.setupDrawColorFilter();
+        renderer.setupDrawShader();
+        renderer.setupDrawBlending(true, mode);
+        renderer.setupDrawProgram();
+        renderer.setupDrawModelView(x, y, x, y, pureTranslate, true);
+        // Calling setupDrawTexture with the name 0 will enable the
+        // uv attributes and increase the texture unit count
+        // texture binding will be performed by the font renderer as
+        // needed
+        renderer.setupDrawTexture(0);
+        renderer.setupDrawPureColorUniforms();
+        renderer.setupDrawColorFilterUniforms();
+        renderer.setupDrawShaderUniforms(pureTranslate);
+        renderer.setupDrawTextGammaUniforms();
+
+        return NO_ERROR;
+    }
+
+    OpenGLRenderer& renderer;
+    float x;
+    float y;
+    bool pureTranslate;
+    int alpha;
+    SkXfermode::Mode mode;
+    SkPaint* paint;
+};
+
 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
@@ -2591,31 +2755,16 @@
     if (pureTranslate && !linearFilter) {
         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
     }
-
-    mCaches.activeTexture(0);
-    setupDraw();
-    setupDrawTextGamma(paint);
-    setupDrawDirtyRegionsDisabled();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(true, mode);
-    setupDrawProgram();
-    setupDrawModelView(x, y, x, y, pureTranslate, true);
-    setupDrawTexture(fontRenderer.getTexture(linearFilter));
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms(pureTranslate);
-    setupDrawTextGammaUniforms();
+    fontRenderer.setTextureFiltering(linearFilter);
 
     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     const bool hasActiveLayer = hasLayer();
 
+    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-            positions, hasActiveLayer ? &bounds : NULL)) {
+            positions, hasActiveLayer ? &bounds : NULL, &functor)) {
         if (hasActiveLayer) {
             if (!pureTranslate) {
                 currentTransform().mapRect(bounds);
@@ -2633,16 +2782,7 @@
         fontTransform = mat4::identity();
     } else {
         if (CC_UNLIKELY(transform.isPerspective())) {
-            // When the below condition is true, we are rendering text with a
-            // perspective transform inside a layer (either an inline layer
-            // created by Canvas.saveLayer() or a hardware layer.)
-            if (hasLayer() || getTargetFbo() != 0) {
-                float sx, sy;
-                currentTransform().decomposeScale(sx, sy);
-                fontTransform.loadScale(sx, sy, 1.0f);
-            } else {
-                fontTransform = mat4::identity();
-            }
+            fontTransform = mat4::identity();
         } else {
             float sx, sy;
             currentTransform().decomposeScale(sx, sy);
@@ -2717,40 +2857,22 @@
 
     // Pick the appropriate texture filtering
     bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
-
-    // The font renderer will always use texture unit 0
-    mCaches.activeTexture(0);
-    setupDraw();
-    setupDrawTextGamma(paint);
-    setupDrawDirtyRegionsDisabled();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(true, mode);
-    setupDrawProgram();
-    setupDrawModelView(x, y, x, y, pureTranslate, true);
-    // See comment above; the font renderer must use texture unit 0
-    // assert(mTextureUnit == 0)
-    setupDrawTexture(fontRenderer.getTexture(linearFilter));
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms(pureTranslate);
-    setupDrawTextGammaUniforms();
+    fontRenderer.setTextureFiltering(linearFilter);
 
     // TODO: Implement better clipping for scaled/rotated text
     const Rect* clip = !pureTranslate ? NULL : mSnapshot->clipRect;
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
+    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
     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);
+                positions, hasActiveLayer ? &bounds : NULL, &functor);
     } else {
         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL);
+                positions, hasActiveLayer ? &bounds : NULL, &functor);
     }
 
     if (status && hasActiveLayer) {
@@ -2773,12 +2895,12 @@
 
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, mat4::identity());
+    fontRenderer.setTextureFiltering(true);
 
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    mCaches.activeTexture(0);
     setupDraw();
     setupDrawTextGamma(paint);
     setupDrawDirtyRegionsDisabled();
@@ -2789,7 +2911,11 @@
     setupDrawBlending(true, mode);
     setupDrawProgram();
     setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
-    setupDrawTexture(fontRenderer.getTexture(true));
+    // Calling setupDrawTexture with the name 0 will enable the
+    // uv attributes and increase the texture unit count
+    // texture binding will be performed by the font renderer as
+    // needed
+    setupDrawTexture(0);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
     setupDrawShaderUniforms(false);
@@ -2828,7 +2954,7 @@
     return DrawGlInfo::kStatusDrew;
 }
 
-status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
+status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
     if (!layer) {
         return DrawGlInfo::kStatusDone;
     }
@@ -2866,7 +2992,7 @@
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
-            const float a = layer->getAlpha() / 255.0f;
+            const float a = getLayerAlpha(layer);
             setupDraw();
             setupDrawWithTexture();
             setupDrawColor(a, a, a, a);
@@ -2973,12 +3099,8 @@
     mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
 }
 
-SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint, bool alwaysCopy) {
+SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
     if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
-        if (CC_UNLIKELY(alwaysCopy)) {
-            mFilteredPaint = *paint;
-            return &mFilteredPaint;
-        }
         return paint;
     }
 
@@ -3326,10 +3448,24 @@
     TextureVertex::setUV(v++, u2, v2);
 }
 
-void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
+void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
     getAlphaAndModeDirect(paint, alpha,  mode);
+    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
+        // if drawing a layer, ignore the paint's alpha
+        *alpha = mDrawModifiers.mOverrideLayerAlpha;
+    }
     *alpha *= mSnapshot->alpha;
 }
 
+float OpenGLRenderer::getLayerAlpha(Layer* layer) const {
+    float alpha;
+    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
+        alpha = mDrawModifiers.mOverrideLayerAlpha;
+    } else {
+        alpha = layer->getAlpha() / 255.0f;
+    }
+    return alpha * mSnapshot->alpha;
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e961af2..dd7a5a2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -51,6 +51,7 @@
 struct DrawModifiers {
     SkiaShader* mShader;
     SkiaColorFilter* mColorFilter;
+    float mOverrideLayerAlpha;
 
     // Drop shadow
     bool mHasShadow;
@@ -65,15 +66,19 @@
     int mPaintFilterSetBits;
 };
 
+enum StateDeferFlags {
+    kStateDeferFlag_Draw = 0x1,
+    kStateDeferFlag_Clip = 0x2
+};
+
 struct DeferredDisplayState {
     Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
-    int mMultipliedAlpha; // -1 if invalid (because caching not set)
 
     // the below are set and used by the OpenGLRenderer at record and deferred playback
     Rect mClip;
     mat4 mMatrix;
-    SkiaShader* mShader;
     DrawModifiers mDrawModifiers;
+    float mAlpha;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -81,6 +86,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class DisplayList;
+class TextSetupFunctor;
 class VertexBuffer;
 
 /**
@@ -188,10 +194,21 @@
     virtual void restore();
     virtual void restoreToCount(int saveCount);
 
+    ANDROID_API int saveLayer(float left, float top, float right, float bottom,
+            SkPaint* paint, int flags) {
+        SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
+        if (paint) mode = getXfermode(paint->getXfermode());
+        return saveLayer(left, top, right, bottom, paint ? paint->getAlpha() : 255, mode, flags);
+    }
+    ANDROID_API int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, int flags) {
+        return saveLayer(left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
+    }
     virtual int saveLayer(float left, float top, float right, float bottom,
-            SkPaint* p, int flags);
-    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, int flags);
+            int alpha, SkXfermode::Mode mode, int flags);
+
+    int saveLayerDeferred(float left, float top, float right, float bottom,
+            int alpha, SkXfermode::Mode mode, int flags);
 
     virtual void translate(float dx, float dy);
     virtual void rotate(float degrees);
@@ -211,9 +228,9 @@
     virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
     virtual Rect* getClipRect();
 
-    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
+    virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags);
     virtual void outputDisplayList(DisplayList* displayList);
-    virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
+    virtual status_t drawLayer(Layer* layer, float x, float y);
     virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
@@ -259,18 +276,12 @@
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
-    SkPaint* filterPaint(SkPaint* paint, bool alwaysCopy = false);
+    // If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
+    void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
 
-    bool disallowDeferral() {
-        // returns true if the OpenGLRenderer's state can be completely represented by
-        // a DeferredDisplayState object
-        return !mSnapshot->clipRegion->isEmpty() ||
-                mSnapshot->alpha < 1.0 ||
-                (mSnapshot->flags & Snapshot::kFlagIsLayer) ||
-                (mSnapshot->flags & Snapshot::kFlagFboTarget); // ensure we're not in a layer
-    }
+    SkPaint* filterPaint(SkPaint* paint);
 
-    bool storeDisplayState(DeferredDisplayState& state);
+    bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
     void restoreDisplayState(const DeferredDisplayState& state);
 
     const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
@@ -284,12 +295,17 @@
         return mCaches;
     }
 
+    // simple rect clip
+    bool isCurrentClipSimple() {
+        return mSnapshot->clipRegion->isEmpty();
+    }
+
     /**
-     * Sets the alpha on the current snapshot. This alpha value will be modulated
+     * Scales the alpha on the current snapshot. This alpha value will be modulated
      * with other alpha values when drawing primitives.
      */
-    void setAlpha(float alpha) {
-        mSnapshot->alpha = alpha;
+    void scaleAlpha(float alpha) {
+        mSnapshot->alpha *= alpha;
     }
 
     /**
@@ -312,7 +328,8 @@
     /**
      * Gets the alpha and xfermode out of a paint object. If the paint is null
      * alpha will be 255 and the xfermode will be SRC_OVER. This method does
-     * not multiply the paint's alpha by the current snapshot's alpha.
+     * not multiply the paint's alpha by the current snapshot's alpha, and does
+     * not replace the alpha with the overrideLayerAlpha
      *
      * @param paint The paint to extract values from
      * @param alpha Where to store the resulting alpha
@@ -349,6 +366,18 @@
     void initViewport(int width, int height);
 
     /**
+     * Perform the setup specific to a frame. This method does not
+     * issue any OpenGL commands.
+     */
+    void setupFrameState(float left, float top, float right, float bottom, bool opaque);
+
+    /**
+     * Indicates the start of rendering. This method will setup the
+     * initial OpenGL state (viewport, clearing the buffer, etc.)
+     */
+    status_t startFrame();
+
+    /**
      * Clears the underlying surface if needed.
      */
     virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
@@ -425,13 +454,21 @@
 
     /**
      * Gets the alpha and xfermode out of a paint object. If the paint is null
-     * alpha will be 255 and the xfermode will be SRC_OVER.
+     * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for both
+     * snapshot alpha, and overrideLayerAlpha
      *
      * @param paint The paint to extract values from
      * @param alpha Where to store the resulting alpha
      * @param mode Where to store the resulting xfermode
      */
-    inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
+    inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const;
+
+    /**
+     * Gets the alpha from a layer, accounting for snapshot alpha and overrideLayerAlpha
+     *
+     * @param layer The layer from which the alpha is extracted
+     */
+    inline float getLayerAlpha(Layer* layer) const;
 
     /**
      * Safely retrieves the mode from the specified xfermode. If the specified
@@ -531,6 +568,17 @@
     bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
 
     /**
+     * Given the local bounds of the layer, calculates ...
+     */
+    void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer);
+
+    /**
+     * Given the local bounds + clip of the layer, updates current snapshot's empty/invisible
+     */
+    void updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
+            bool fboLayer, int alpha);
+
+    /**
      * Creates a new layer stored in the specified snapshot.
      *
      * @param snapshot The snapshot associated with the new layer
@@ -879,6 +927,7 @@
 
     bool updateLayer(Layer* layer, bool inFrame);
     void updateLayers();
+    void flushLayers();
 
     /**
      * Renders the specified region as a series of rectangles. This method
@@ -929,7 +978,11 @@
     // Current state
     sp<Snapshot> mSnapshot;
     // State used to define the clipping region
-    sp<Snapshot> mTilingSnapshot;
+    Rect mTilingClip;
+    // Is the target render surface opaque
+    bool mOpaque;
+    // Is a frame currently being rendered
+    bool mFrameStarted;
 
     // Used to draw textured quads
     TextureVertex mMeshVertices[4];
@@ -978,6 +1031,8 @@
     String8 mName;
 
     friend class DisplayListRenderer;
+    friend class Layer;
+    friend class TextSetupFunctor;
 
 }; // class OpenGLRenderer
 
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 4f682ed..fdb10e2 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 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.
@@ -15,24 +15,85 @@
  */
 
 #define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
 
-#include <utils/threads.h>
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkRect.h>
 
+#include <utils/JenkinsHash.h>
+#include <utils/Trace.h>
+
+#include "Caches.h"
 #include "PathCache.h"
-#include "Properties.h"
+
+#include "thread/Signal.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
 
 namespace android {
 namespace uirenderer {
 
-// Defined in ShapeCache.h
+///////////////////////////////////////////////////////////////////////////////
+// Cache entries
+///////////////////////////////////////////////////////////////////////////////
 
-void computePathBounds(const SkPath* path, const SkPaint* paint,
-        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
-    const SkRect& bounds = path->getBounds();
-    computeBounds(bounds, paint, left, top, offset, width, height);
+PathDescription::PathDescription():
+        type(kShapeNone),
+        join(SkPaint::kDefault_Join),
+        cap(SkPaint::kDefault_Cap),
+        style(SkPaint::kFill_Style),
+        miter(4.0f),
+        strokeWidth(1.0f),
+        pathEffect(NULL) {
+    memset(&shape, 0, sizeof(Shape));
 }
 
-void computeBounds(const SkRect& bounds, const SkPaint* paint,
+PathDescription::PathDescription(ShapeType type, SkPaint* paint):
+        type(type),
+        join(paint->getStrokeJoin()),
+        cap(paint->getStrokeCap()),
+        style(paint->getStyle()),
+        miter(paint->getStrokeMiter()),
+        strokeWidth(paint->getStrokeWidth()),
+        pathEffect(paint->getPathEffect()) {
+    memset(&shape, 0, sizeof(Shape));
+}
+
+hash_t PathDescription::hash() const {
+    uint32_t hash = JenkinsHashMix(0, type);
+    hash = JenkinsHashMix(hash, join);
+    hash = JenkinsHashMix(hash, cap);
+    hash = JenkinsHashMix(hash, style);
+    hash = JenkinsHashMix(hash, android::hash_type(miter));
+    hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
+    hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
+    hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+    return JenkinsHashWhiten(hash);
+}
+
+int PathDescription::compare(const PathDescription& rhs) const {
+    return memcmp(this, &rhs, sizeof(PathDescription));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Utilities
+///////////////////////////////////////////////////////////////////////////////
+
+bool PathCache::canDrawAsConvexPath(SkPath* path, SkPaint* paint) {
+    // NOTE: This should only be used after PathTessellator handles joins properly
+    return paint->getPathEffect() == NULL && path->getConvexity() == SkPath::kConvex_Convexity;
+}
+
+void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
+        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
+    const SkRect& bounds = path->getBounds();
+    PathCache::computeBounds(bounds, paint, left, top, offset, width, height);
+}
+
+void PathCache::computeBounds(const SkRect& bounds, const SkPaint* paint,
         float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
     const float pathWidth = fmax(bounds.width(), 1.0f);
     const float pathHeight = fmax(bounds.height(), 1.0f);
@@ -46,21 +107,258 @@
     height = uint32_t(pathHeight + offset * 2.0 + 0.5);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Path cache
-///////////////////////////////////////////////////////////////////////////////
-
-PathCache::PathCache(): ShapeCache<PathCacheEntry>("path",
-        PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE) {
+static void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
+    bitmap.setConfig(SkBitmap::kA8_Config, width, height);
+    bitmap.allocPixels();
+    bitmap.eraseColor(0);
 }
 
-void PathCache::remove(SkPath* path) {
-    Vector<PathCacheEntry> pathsToRemove;
-    LruCache<PathCacheEntry, PathTexture*>::Iterator i(mCache);
+static void initPaint(SkPaint& paint) {
+    // Make sure the paint is opaque, color, alpha, filter, etc.
+    // will be applied later when compositing the alpha8 texture
+    paint.setColor(0xff000000);
+    paint.setAlpha(255);
+    paint.setColorFilter(NULL);
+    paint.setMaskFilter(NULL);
+    paint.setShader(NULL);
+    SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
+    SkSafeUnref(paint.setXfermode(mode));
+}
+
+static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap,
+        float left, float top, float offset, uint32_t width, uint32_t height) {
+    initBitmap(bitmap, width, height);
+
+    SkPaint pathPaint(*paint);
+    initPaint(pathPaint);
+
+    SkCanvas canvas(bitmap);
+    canvas.translate(-left + offset, -top + offset);
+    canvas.drawPath(*path, pathPaint);
+}
+
+static PathTexture* createTexture(float left, float top, float offset,
+        uint32_t width, uint32_t height, uint32_t id) {
+    PathTexture* texture = new PathTexture();
+    texture->left = left;
+    texture->top = top;
+    texture->offset = offset;
+    texture->width = width;
+    texture->height = height;
+    texture->generation = id;
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache constructor/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+PathCache::PathCache():
+        mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity),
+        mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
+        INIT_LOGD("  Setting %s cache size to %sMB", name, property);
+        setMaxSize(MB(atof(property)));
+    } else {
+        INIT_LOGD("  Using default %s cache size of %.2fMB", name, DEFAULT_PATH_CACHE_SIZE);
+    }
+    init();
+}
+
+PathCache::~PathCache() {
+    mCache.clear();
+}
+
+void PathCache::init() {
+    mCache.setOnEntryRemovedListener(this);
+
+    GLint maxTextureSize;
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+    mMaxTextureSize = maxTextureSize;
+
+    mDebugEnabled = readDebugLevel() & kDebugCaches;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t PathCache::getSize() {
+    return mSize;
+}
+
+uint32_t PathCache::getMaxSize() {
+    return mMaxSize;
+}
+
+void PathCache::setMaxSize(uint32_t maxSize) {
+    mMaxSize = maxSize;
+    while (mSize > mMaxSize) {
+        mCache.removeOldest();
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void PathCache::operator()(PathDescription& entry, PathTexture*& texture) {
+    removeTexture(texture);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+void PathCache::removeTexture(PathTexture* texture) {
+    if (texture) {
+        const uint32_t size = texture->width * texture->height;
+        mSize -= size;
+
+        PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
+                texture->id, size, mSize);
+        if (mDebugEnabled) {
+            ALOGD("Shape deleted, size = %d", size);
+        }
+
+        if (texture->id) {
+            glDeleteTextures(1, &texture->id);
+        }
+        delete texture;
+    }
+}
+
+void PathCache::purgeCache(uint32_t width, uint32_t height) {
+    const uint32_t size = width * height;
+    // Don't even try to cache a bitmap that's bigger than the cache
+    if (size < mMaxSize) {
+        while (mSize + size > mMaxSize) {
+            mCache.removeOldest();
+        }
+    }
+}
+
+void PathCache::trim() {
+    while (mSize > mMaxSize) {
+        mCache.removeOldest();
+    }
+}
+
+PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
+        const SkPaint* paint) {
+    ATRACE_CALL();
+
+    float left, top, offset;
+    uint32_t width, height;
+    computePathBounds(path, paint, left, top, offset, width, height);
+
+    if (!checkTextureSize(width, height)) return NULL;
+
+    purgeCache(width, height);
+
+    SkBitmap bitmap;
+    drawPath(path, paint, bitmap, left, top, offset, width, height);
+
+    PathTexture* texture = createTexture(left, top, offset, width, height,
+            path->getGenerationID());
+    generateTexture(entry, &bitmap, texture);
+
+    return texture;
+}
+
+void PathCache::generateTexture(const PathDescription& entry, SkBitmap* bitmap,
+        PathTexture* texture, bool addToCache) {
+    generateTexture(*bitmap, texture);
+
+    uint32_t size = texture->width * texture->height;
+    if (size < mMaxSize) {
+        mSize += size;
+        PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
+                texture->id, size, mSize);
+        if (mDebugEnabled) {
+            ALOGD("Shape created, size = %d", size);
+        }
+        if (addToCache) {
+            mCache.put(entry, texture);
+        }
+    } else {
+        texture->cleanup = true;
+    }
+}
+
+void PathCache::clear() {
+    mCache.clear();
+}
+
+void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
+    SkAutoLockPixels alp(bitmap);
+    if (!bitmap.readyToDraw()) {
+        ALOGE("Cannot generate texture from bitmap");
+        return;
+    }
+
+    glGenTextures(1, &texture->id);
+
+    glBindTexture(GL_TEXTURE_2D, texture->id);
+    // Textures are Alpha8
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    texture->blend = true;
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
+            GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
+
+    texture->setFilter(GL_LINEAR);
+    texture->setWrap(GL_CLAMP_TO_EDGE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Path precaching
+///////////////////////////////////////////////////////////////////////////////
+
+PathCache::PathProcessor::PathProcessor(Caches& caches):
+        TaskProcessor<SkBitmap*>(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
+}
+
+void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
+    sp<PathTask> t = static_cast<PathTask* >(task.get());
+    ATRACE_NAME("pathPrecache");
+
+    float left, top, offset;
+    uint32_t width, height;
+    PathCache::computePathBounds(t->path, t->paint, left, top, offset, width, height);
+
+    PathTexture* texture = t->texture;
+    texture->left = left;
+    texture->top = top;
+    texture->offset = offset;
+    texture->width = width;
+    texture->height = height;
+
+    if (width <= mMaxTextureSize && height <= mMaxTextureSize) {
+        SkBitmap* bitmap = new SkBitmap();
+        drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height);
+        t->setResult(bitmap);
+    } else {
+        texture->width = 0;
+        texture->height = 0;
+        t->setResult(NULL);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Paths
+///////////////////////////////////////////////////////////////////////////////
+
+void PathCache::remove(const path_pair_t& pair) {
+    Vector<PathDescription> pathsToRemove;
+    LruCache<PathDescription, PathTexture*>::Iterator i(mCache);
 
     while (i.next()) {
-        const PathCacheEntry& key = i.key();
-        if (key.path == path) {
+        const PathDescription& key = i.key();
+        if (key.type == kShapePath &&
+                (key.shape.path.mPath == pair.getFirst() ||
+                        key.shape.path.mPath == pair.getSecond())) {
             pathsToRemove.push(key);
         }
     }
@@ -71,12 +369,12 @@
 }
 
 void PathCache::removeDeferred(SkPath* path) {
-    Mutex::Autolock _l(mLock);
-    mGarbage.push(path);
+    Mutex::Autolock l(mLock);
+    mGarbage.push(path_pair_t(path, const_cast<SkPath*>(path->getSourcePath())));
 }
 
 void PathCache::clearGarbage() {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock l(mLock);
     size_t count = mGarbage.size();
     for (size_t i = 0; i < count; i++) {
         remove(mGarbage.itemAt(i));
@@ -84,20 +382,223 @@
     mGarbage.clear();
 }
 
-PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
+/**
+ * To properly handle path mutations at draw time we always make a copy
+ * of paths objects when recording display lists. The source path points
+ * to the path we originally copied the path from. This ensures we use
+ * the original path as a cache key the first time a path is inserted
+ * in the cache. The source path is also used to reclaim garbage when a
+ * Dalvik Path object is collected.
+ */
+static SkPath* getSourcePath(SkPath* path) {
     const SkPath* sourcePath = path->getSourcePath();
     if (sourcePath && sourcePath->getGenerationID() == path->getGenerationID()) {
-        path = const_cast<SkPath*>(sourcePath);
+        return const_cast<SkPath*>(sourcePath);
     }
+    return path;
+}
 
-    PathCacheEntry entry(path, paint);
+PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
+    path = getSourcePath(path);
+
+    PathDescription entry(kShapePath, paint);
+    entry.shape.path.mPath = path;
+
     PathTexture* texture = mCache.get(entry);
 
     if (!texture) {
         texture = addTexture(entry, path, paint);
+    } else {
+        // A bitmap is attached to the texture, this means we need to
+        // upload it as a GL texture
+        const sp<Task<SkBitmap*> >& task = texture->task();
+        if (task != NULL) {
+            // But we must first wait for the worker thread to be done
+            // producing the bitmap, so let's wait
+            SkBitmap* bitmap = task->getResult();
+            if (bitmap) {
+                generateTexture(entry, bitmap, texture, false);
+                texture->clearTask();
+            } else {
+                ALOGW("Path too large to be rendered into a texture");
+                texture->clearTask();
+                texture = NULL;
+                mCache.remove(entry);
+            }
+        } else if (path->getGenerationID() != texture->generation) {
+            // The size of the path might have changed so we first
+            // remove the entry from the cache
+            mCache.remove(entry);
+            texture = addTexture(entry, path, paint);
+        }
+    }
+
+    return texture;
+}
+
+void PathCache::precache(SkPath* path, SkPaint* paint) {
+    if (!Caches::getInstance().tasks.canRunTasks()) {
+        return;
+    }
+
+    path = getSourcePath(path);
+
+    PathDescription entry(kShapePath, paint);
+    entry.shape.path.mPath = path;
+
+    PathTexture* texture = mCache.get(entry);
+
+    bool generate = false;
+    if (!texture) {
+        generate = true;
     } else if (path->getGenerationID() != texture->generation) {
         mCache.remove(entry);
-        texture = addTexture(entry, path, paint);
+        generate = true;
+    }
+
+    if (generate) {
+        // It is important to specify the generation ID so we do not
+        // attempt to precache the same path several times
+        texture = createTexture(0.0f, 0.0f, 0.0f, 0, 0, path->getGenerationID());
+        sp<PathTask> task = new PathTask(path, paint, texture);
+        texture->setTask(task);
+
+        // During the precaching phase we insert path texture objects into
+        // the cache that do not point to any GL texture. They are instead
+        // treated as a task for the precaching worker thread. This is why
+        // we do not check the cache limit when inserting these objects.
+        // The conversion into GL texture will happen in get(), when a client
+        // asks for a path texture. This is also when the cache limit will
+        // be enforced.
+        mCache.put(entry, texture);
+
+        if (mProcessor == NULL) {
+            mProcessor = new PathProcessor(Caches::getInstance());
+        }
+        mProcessor->add(task);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Rounded rects
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getRoundRect(float width, float height,
+        float rx, float ry, SkPaint* paint) {
+    PathDescription entry(kShapeRoundRect, paint);
+    entry.shape.roundRect.mWidth = width;
+    entry.shape.roundRect.mHeight = height;
+    entry.shape.roundRect.mRx = rx;
+    entry.shape.roundRect.mRy = ry;
+
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        SkRect r;
+        r.set(0.0f, 0.0f, width, height);
+        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Circles
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getCircle(float radius, SkPaint* paint) {
+    PathDescription entry(kShapeCircle, paint);
+    entry.shape.circle.mRadius = radius;
+
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Ovals
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getOval(float width, float height, SkPaint* paint) {
+    PathDescription entry(kShapeOval, paint);
+    entry.shape.oval.mWidth = width;
+    entry.shape.oval.mHeight = height;
+
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        SkRect r;
+        r.set(0.0f, 0.0f, width, height);
+        path.addOval(r, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Rects
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getRect(float width, float height, SkPaint* paint) {
+    PathDescription entry(kShapeRect, paint);
+    entry.shape.rect.mWidth = width;
+    entry.shape.rect.mHeight = height;
+
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        SkRect r;
+        r.set(0.0f, 0.0f, width, height);
+        path.addRect(r, SkPath::kCW_Direction);
+
+        texture = addTexture(entry, &path, paint);
+    }
+
+    return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Arcs
+///////////////////////////////////////////////////////////////////////////////
+
+PathTexture* PathCache::getArc(float width, float height,
+        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
+    PathDescription entry(kShapeArc, paint);
+    entry.shape.arc.mWidth = width;
+    entry.shape.arc.mHeight = height;
+    entry.shape.arc.mStartAngle = startAngle;
+    entry.shape.arc.mSweepAngle = sweepAngle;
+    entry.shape.arc.mUseCenter = useCenter;
+
+    PathTexture* texture = get(entry);
+
+    if (!texture) {
+        SkPath path;
+        SkRect r;
+        r.set(0.0f, 0.0f, width, height);
+        if (useCenter) {
+            path.moveTo(r.centerX(), r.centerY());
+        }
+        path.arcTo(r, startAngle, sweepAngle, !useCenter);
+        if (useCenter) {
+            path.close();
+        }
+
+        texture = addTexture(entry, &path, paint);
     }
 
     return texture;
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 8a0235b..dd1f996 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 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.
@@ -17,68 +17,204 @@
 #ifndef ANDROID_HWUI_PATH_CACHE_H
 #define ANDROID_HWUI_PATH_CACHE_H
 
+#include <GLES2/gl2.h>
+
+#include <utils/LruCache.h>
+#include <utils/Mutex.h>
 #include <utils/Vector.h>
 
 #include "Debug.h"
-#include "ShapeCache.h"
+#include "Properties.h"
+#include "Texture.h"
+#include "utils/Pair.h"
+
+class SkBitmap;
+class SkCanvas;
+class SkPaint;
+class SkPath;
+class SkRect;
 
 namespace android {
 namespace uirenderer {
 
+class Caches;
+
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#if DEBUG_PATHS
+    #define PATH_LOGD(...) ALOGD(__VA_ARGS__)
+#else
+    #define PATH_LOGD(...)
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // Classes
 ///////////////////////////////////////////////////////////////////////////////
 
-struct PathCacheEntry: public ShapeCacheEntry {
-    PathCacheEntry(SkPath* path, SkPaint* paint):
-            ShapeCacheEntry(ShapeCacheEntry::kShapePath, paint) {
-        this->path = path;
+/**
+ * Alpha texture used to represent a path.
+ */
+struct PathTexture: public Texture {
+    PathTexture(): Texture() {
     }
 
-    PathCacheEntry(): ShapeCacheEntry() {
-        path = NULL;
+    ~PathTexture() {
+        clearTask();
     }
 
-    hash_t hash() const {
-        uint32_t hash = ShapeCacheEntry::hash();
-        hash = JenkinsHashMix(hash, android::hash_type(path));
-        return JenkinsHashWhiten(hash);
+    /**
+     * Left coordinate of the path bounds.
+     */
+    float left;
+    /**
+     * Top coordinate of the path bounds.
+     */
+    float top;
+    /**
+     * Offset to draw the path at the correct origin.
+     */
+    float offset;
+
+    sp<Task<SkBitmap*> > task() const {
+        return mTask;
     }
 
-    int compare(const ShapeCacheEntry& r) const {
-        int deltaInt = ShapeCacheEntry::compare(r);
-        if (deltaInt != 0) return deltaInt;
-
-        const PathCacheEntry& rhs = (const PathCacheEntry&) r;
-        return path - rhs.path;
+    void setTask(const sp<Task<SkBitmap*> >& task) {
+        mTask = task;
     }
 
-    SkPath* path;
+    void clearTask() {
+        if (mTask != NULL) {
+            mTask.clear();
+        }
+    }
 
-}; // PathCacheEntry
+private:
+    sp<Task<SkBitmap*> > mTask;
+}; // struct PathTexture
 
-inline hash_t hash_type(const PathCacheEntry& entry) {
-    return entry.hash();
-}
+enum ShapeType {
+    kShapeNone,
+    kShapeRect,
+    kShapeRoundRect,
+    kShapeCircle,
+    kShapeOval,
+    kShapeArc,
+    kShapePath
+};
+
+struct PathDescription {
+    ShapeType type;
+    SkPaint::Join join;
+    SkPaint::Cap cap;
+    SkPaint::Style style;
+    float miter;
+    float strokeWidth;
+    SkPathEffect* pathEffect;
+    union Shape {
+        struct Path {
+            SkPath* mPath;
+        } path;
+        struct RoundRect {
+            float mWidth;
+            float mHeight;
+            float mRx;
+            float mRy;
+        } roundRect;
+        struct Circle {
+            float mRadius;
+        } circle;
+        struct Oval {
+            float mWidth;
+            float mHeight;
+        } oval;
+        struct Rect {
+            float mWidth;
+            float mHeight;
+        } rect;
+        struct Arc {
+            float mWidth;
+            float mHeight;
+            float mStartAngle;
+            float mSweepAngle;
+            bool mUseCenter;
+        } arc;
+    } shape;
+
+    PathDescription();
+    PathDescription(ShapeType shapeType, SkPaint* paint);
+
+    hash_t hash() const;
+
+    int compare(const PathDescription& rhs) const;
+
+    bool operator==(const PathDescription& other) const {
+        return compare(other) == 0;
+    }
+
+    bool operator!=(const PathDescription& other) const {
+        return compare(other) != 0;
+    }
+
+    friend inline int strictly_order_type(
+            const PathDescription& lhs, const PathDescription& rhs) {
+        return lhs.compare(rhs) < 0;
+    }
+
+    friend inline int compare_type(const PathDescription& lhs, const PathDescription& rhs) {
+        return lhs.compare(rhs);
+    }
+
+    friend inline hash_t hash_type(const PathDescription& entry) {
+        return entry.hash();
+    }
+};
 
 /**
- * A simple LRU path cache. The cache has a maximum size expressed in bytes.
+ * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
  * Any texture added to the cache causing the cache to grow beyond the maximum
  * allowed size will also cause the oldest texture to be kicked out.
  */
-class PathCache: public ShapeCache<PathCacheEntry> {
+class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
 public:
     PathCache();
+    ~PathCache();
 
     /**
-     * Returns the texture associated with the specified path. If the texture
-     * cannot be found in the cache, a new texture is generated.
+     * Used as a callback when an entry is removed from the cache.
+     * Do not invoke directly.
      */
-    PathTexture* get(SkPath* path, SkPaint* paint);
+    void operator()(PathDescription& path, PathTexture*& texture);
+
     /**
-     * Removes an entry.
+     * Clears the cache. This causes all textures to be deleted.
      */
-    void remove(SkPath* path);
+    void clear();
+
+    /**
+     * Sets the maximum size of the cache in bytes.
+     */
+    void setMaxSize(uint32_t maxSize);
+    /**
+     * Returns the maximum size of the cache in bytes.
+     */
+    uint32_t getMaxSize();
+    /**
+     * Returns the current size of the cache in bytes.
+     */
+    uint32_t getSize();
+
+    PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint);
+    PathTexture* getCircle(float radius, SkPaint* paint);
+    PathTexture* getOval(float width, float height, SkPaint* paint);
+    PathTexture* getRect(float width, float height, SkPaint* paint);
+    PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
+            bool useCenter, SkPaint* paint);
+    PathTexture* get(SkPath* path, SkPaint* paint);
+
     /**
      * Removes the specified path. This is meant to be called from threads
      * that are not the EGL context thread.
@@ -88,9 +224,108 @@
      * Process deferred removals.
      */
     void clearGarbage();
+    /**
+     * Trims the contents of the cache, removing items until it's under its
+     * specified limit.
+     *
+     * Trimming is used for caches that support pre-caching from a worker
+     * thread. During pre-caching the maximum limit of the cache can be
+     * exceeded for the duration of the frame. It is therefore required to
+     * trim the cache at the end of the frame to keep the total amount of
+     * memory used under control.
+     */
+    void trim();
+
+    /**
+     * Precaches the specified path using background threads.
+     */
+    void precache(SkPath* path, SkPaint* paint);
+
+    static bool canDrawAsConvexPath(SkPath* path, SkPaint* paint);
+    static void computePathBounds(const SkPath* path, const SkPaint* paint,
+            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+    static void computeBounds(const SkRect& bounds, const SkPaint* paint,
+            float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
 
 private:
-    Vector<SkPath*> mGarbage;
+    typedef Pair<SkPath*, SkPath*> path_pair_t;
+
+    PathTexture* addTexture(const PathDescription& entry,
+            const SkPath *path, const SkPaint* paint);
+    PathTexture* addTexture(const PathDescription& entry, SkBitmap* bitmap);
+
+    /**
+     * Generates the texture from a bitmap into the specified texture structure.
+     */
+    void generateTexture(SkBitmap& bitmap, Texture* texture);
+    void generateTexture(const PathDescription& entry, SkBitmap* bitmap, PathTexture* texture,
+            bool addToCache = true);
+
+    PathTexture* get(const PathDescription& entry) {
+        return mCache.get(entry);
+    }
+
+    /**
+     * Removes an entry.
+     * The pair must define first=path, second=sourcePath
+     */
+    void remove(const path_pair_t& pair);
+
+    /**
+     * Ensures there is enough space in the cache for a texture of the specified
+     * dimensions.
+     */
+    void purgeCache(uint32_t width, uint32_t height);
+
+    void removeTexture(PathTexture* texture);
+
+    bool checkTextureSize(uint32_t width, uint32_t height) {
+        if (width > mMaxTextureSize || height > mMaxTextureSize) {
+            ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
+                    width, height, mMaxTextureSize, mMaxTextureSize);
+            return false;
+        }
+        return true;
+    }
+
+    void init();
+
+    class PathTask: public Task<SkBitmap*> {
+    public:
+        PathTask(SkPath* path, SkPaint* paint, PathTexture* texture):
+            path(path), paint(paint), texture(texture) {
+        }
+
+        ~PathTask() {
+            delete future()->get();
+        }
+
+        SkPath* path;
+        SkPaint* paint;
+        PathTexture* texture;
+    };
+
+    class PathProcessor: public TaskProcessor<SkBitmap*> {
+    public:
+        PathProcessor(Caches& caches);
+        ~PathProcessor() { }
+
+        virtual void onProcess(const sp<Task<SkBitmap*> >& task);
+
+    private:
+        uint32_t mMaxTextureSize;
+    };
+
+    LruCache<PathDescription, PathTexture*> mCache;
+    uint32_t mSize;
+    uint32_t mMaxSize;
+    GLuint mMaxTextureSize;
+
+    bool mDebugEnabled;
+
+    sp<PathProcessor> mProcessor;
+
+    Vector<path_pair_t> mGarbage;
     mutable Mutex mLock;
 }; // class PathCache
 
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 395bbf6..0879b1b 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -61,6 +61,7 @@
         bool forceExpand) {
     if (forceExpand || paint->getStyle() != SkPaint::kFill_Style) {
         float outset = paint->getStrokeWidth() * 0.5f;
+        if (outset == 0) outset = 0.5f; // account for hairline
         bounds.outset(outset, outset);
     }
 }
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index f78fb2d..8eb85e5 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -19,6 +19,7 @@
 #include <utils/String8.h>
 
 #include "Caches.h"
+#include "Dither.h"
 #include "ProgramCache.h"
 
 namespace android {
@@ -32,6 +33,9 @@
 #define MODULATE_OP_MODULATE 1
 #define MODULATE_OP_MODULATE_A8 2
 
+#define STR(x) STR1(x)
+#define STR1(x) #x
+
 ///////////////////////////////////////////////////////////////////////////////
 // Vertex shaders snippets
 ///////////////////////////////////////////////////////////////////////////////
@@ -51,17 +55,8 @@
         "uniform mat4 transform;\n";
 const char* gVS_Header_Uniforms_IsPoint =
         "uniform mediump float pointSize;\n";
-const char* gVS_Header_Uniforms_HasGradient[3] = {
-        // Linear
-        "uniform mat4 screenSpace;\n"
-        "uniform float ditherSize;\n",
-        // Circular
-        "uniform mat4 screenSpace;\n"
-        "uniform float ditherSize;\n",
-        // Sweep
-        "uniform mat4 screenSpace;\n"
-        "uniform float ditherSize;\n"
-};
+const char* gVS_Header_Uniforms_HasGradient =
+        "uniform mat4 screenSpace;\n";
 const char* gVS_Header_Uniforms_HasBitmap =
         "uniform mat4 textureTransform;\n"
         "uniform mediump vec2 textureDimension;\n";
@@ -105,21 +100,21 @@
 const char* gVS_Main_OutGradient[6] = {
         // Linear
         "    linear = vec2((screenSpace * position).x, 0.5);\n"
-        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
+        "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
         "    linear = (screenSpace * position).x;\n"
-        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
+        "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
 
         // Circular
         "    circular = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
+        "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
         "    circular = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
+        "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
 
         // Sweep
         "    sweep = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
+        "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
         "    sweep = (screenSpace * position).xy;\n"
-        "    ditherTexCoords = (transform * position).xy * ditherSize;\n",
+        "    ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
 };
 const char* gVS_Main_OutBitmapTexCoords =
         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
@@ -153,24 +148,14 @@
         "uniform sampler2D baseSampler;\n";
 const char* gFS_Uniforms_ExternalTextureSampler =
         "uniform samplerExternalOES baseSampler;\n";
-#define FS_UNIFORMS_DITHER \
-        "uniform float ditherSizeSquared;\n" \
-        "uniform sampler2D ditherSampler;\n"
-#define FS_UNIFORMS_GRADIENT \
-        "uniform vec4 startColor;\n" \
+const char* gFS_Uniforms_Dither =
+        "uniform sampler2D ditherSampler;";
+const char* gFS_Uniforms_GradientSampler[2] = {
+        "%s\n"
+        "uniform sampler2D gradientSampler;\n",
+        "%s\n"
+        "uniform vec4 startColor;\n"
         "uniform vec4 endColor;\n"
-const char* gFS_Uniforms_GradientSampler[6] = {
-        // Linear
-        FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
-        FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT,
-
-        // Circular
-        FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
-        FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT,
-
-        // Sweep
-        FS_UNIFORMS_DITHER "uniform sampler2D gradientSampler;\n",
-        FS_UNIFORMS_DITHER FS_UNIFORMS_GRADIENT
 };
 const char* gFS_Uniforms_BitmapSampler =
         "uniform sampler2D bitmapSampler;\n";
@@ -197,10 +182,14 @@
         "    highp vec2 outBitmapTexCoords = outPointBitmapTexCoords + "
         "((gl_PointCoord - vec2(0.5, 0.5)) * textureDimension * vec2(pointSize, pointSize));\n";
 
-#define FS_MAIN_DITHER \
-        "texture2D(ditherSampler, ditherTexCoords).a * ditherSizeSquared"
+const char* gFS_Main_Dither[2] = {
+        // ES 2.0
+        "texture2D(ditherSampler, ditherTexCoords).a * " STR(DITHER_KERNEL_SIZE_INV_SQUARE),
+        // ES 3.0
+        "texture2D(ditherSampler, ditherTexCoords).a"
+};
 const char* gFS_Main_AddDitherToGradient =
-        "    gradientColor += " FS_MAIN_DITHER ";\n";
+        "    gradientColor += %s;\n";
 
 // Fast cases
 const char* gFS_Fast_SingleColor =
@@ -233,18 +222,18 @@
         "}\n\n";
 const char* gFS_Fast_SingleGradient[2] = {
         "\nvoid main(void) {\n"
-        "    gl_FragColor = " FS_MAIN_DITHER " + texture2D(gradientSampler, linear);\n"
+        "    gl_FragColor = %s + texture2D(gradientSampler, linear);\n"
         "}\n\n",
         "\nvoid main(void) {\n"
-        "    gl_FragColor = " FS_MAIN_DITHER " + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
-        "}\n\n"
+        "    gl_FragColor = %s + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+        "}\n\n",
 };
 const char* gFS_Fast_SingleModulateGradient[2] = {
         "\nvoid main(void) {\n"
-        "    gl_FragColor = " FS_MAIN_DITHER " + color.a * texture2D(gradientSampler, linear);\n"
+        "    gl_FragColor = %s + color.a * texture2D(gradientSampler, linear);\n"
         "}\n\n",
         "\nvoid main(void) {\n"
-        "    gl_FragColor = " FS_MAIN_DITHER " + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+        "    gl_FragColor = %s + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
         "}\n\n"
 };
 
@@ -410,7 +399,7 @@
 // Constructors/destructors
 ///////////////////////////////////////////////////////////////////////////////
 
-ProgramCache::ProgramCache() {
+ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
 }
 
 ProgramCache::~ProgramCache() {
@@ -484,7 +473,7 @@
         shader.append(gVS_Header_Uniforms_TextureTransform);
     }
     if (description.hasGradient) {
-        shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
+        shader.append(gVS_Header_Uniforms_HasGradient);
     }
     if (description.hasBitmap) {
         shader.append(gVS_Header_Uniforms_HasBitmap);
@@ -601,7 +590,8 @@
         shader.append(gFS_Uniforms_ExternalTextureSampler);
     }
     if (description.hasGradient) {
-        shader.append(gFS_Uniforms_GradientSampler[gradientIndex(description)]);
+        shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
+                gFS_Uniforms_Dither);
     }
     if (description.hasBitmap && description.isPoint) {
         shader.append(gFS_Header_Uniforms_PointHasBitmap);
@@ -652,9 +642,11 @@
             fast = true;
         } else if (singleGradient) {
             if (!description.modulate) {
-                shader.append(gFS_Fast_SingleGradient[description.isSimpleGradient]);
+                shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient],
+                        gFS_Main_Dither[mHasES3]);
             } else {
-                shader.append(gFS_Fast_SingleModulateGradient[description.isSimpleGradient]);
+                shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient],
+                        gFS_Main_Dither[mHasES3]);
             }
             fast = true;
         }
@@ -708,7 +700,7 @@
         }
         if (description.hasGradient) {
             shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
-            shader.append(gFS_Main_AddDitherToGradient);
+            shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
         }
         if (description.hasBitmap) {
             if (description.isPoint) {
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 1ca148d..38f6f99 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -57,6 +57,8 @@
     void printLongString(const String8& shader) const;
 
     KeyedVector<programid, Program*> mCache;
+
+    const bool mHasES3;
 }; // class ProgramCache
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index b8559bc8..e4b4f3c 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -115,12 +115,11 @@
 #define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size"
 #define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
 #define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
-#define PROPERTY_SHAPE_CACHE_SIZE "ro.hwui.shape_cache_size"
 #define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
 #define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
 
 // These properties are defined in percentage (range 0..1)
-#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flush_rate"
+#define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flushrate"
 
 // These properties are defined in pixels
 #define PROPERTY_TEXT_SMALL_CACHE_WIDTH "ro.hwui.text_small_cache_width"
@@ -159,8 +158,7 @@
 #define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
 #define DEFAULT_LAYER_CACHE_SIZE 16.0f
 #define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
-#define DEFAULT_PATH_CACHE_SIZE 4.0f
-#define DEFAULT_SHAPE_CACHE_SIZE 1.0f
+#define DEFAULT_PATH_CACHE_SIZE 10.0f
 #define DEFAULT_PATCH_CACHE_SIZE 512
 #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
 #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
diff --git a/libs/hwui/ShapeCache.cpp b/libs/hwui/ShapeCache.cpp
deleted file mode 100644
index 5a23235..0000000
--- a/libs/hwui/ShapeCache.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define LOG_TAG "OpenGLRenderer"
-
-#include "ShapeCache.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Rounded rects
-///////////////////////////////////////////////////////////////////////////////
-
-RoundRectShapeCache::RoundRectShapeCache(): ShapeCache<RoundRectShapeCacheEntry>(
-        "round rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* RoundRectShapeCache::getRoundRect(float width, float height,
-        float rx, float ry, SkPaint* paint) {
-    RoundRectShapeCacheEntry entry(width, height, rx, ry, paint);
-    PathTexture* texture = get(entry);
-
-    if (!texture) {
-        SkPath path;
-        SkRect r;
-        r.set(0.0f, 0.0f, width, height);
-        path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
-
-        texture = addTexture(entry, &path, paint);
-    }
-
-    return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Circles
-///////////////////////////////////////////////////////////////////////////////
-
-CircleShapeCache::CircleShapeCache(): ShapeCache<CircleShapeCacheEntry>(
-        "circle", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* CircleShapeCache::getCircle(float radius, SkPaint* paint) {
-    CircleShapeCacheEntry entry(radius, paint);
-    PathTexture* texture = get(entry);
-
-    if (!texture) {
-        SkPath path;
-        path.addCircle(radius, radius, radius, SkPath::kCW_Direction);
-
-        texture = addTexture(entry, &path, paint);
-    }
-
-    return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Ovals
-///////////////////////////////////////////////////////////////////////////////
-
-OvalShapeCache::OvalShapeCache(): ShapeCache<OvalShapeCacheEntry>(
-        "oval", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* OvalShapeCache::getOval(float width, float height, SkPaint* paint) {
-    OvalShapeCacheEntry entry(width, height, paint);
-    PathTexture* texture = get(entry);
-
-    if (!texture) {
-        SkPath path;
-        SkRect r;
-        r.set(0.0f, 0.0f, width, height);
-        path.addOval(r, SkPath::kCW_Direction);
-
-        texture = addTexture(entry, &path, paint);
-    }
-
-    return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Rects
-///////////////////////////////////////////////////////////////////////////////
-
-RectShapeCache::RectShapeCache(): ShapeCache<RectShapeCacheEntry>(
-        "rect", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* RectShapeCache::getRect(float width, float height, SkPaint* paint) {
-    RectShapeCacheEntry entry(width, height, paint);
-    PathTexture* texture = get(entry);
-
-    if (!texture) {
-        SkRect bounds;
-        bounds.set(0.0f, 0.0f, width, height);
-
-        float left, top, offset;
-        uint32_t rectWidth, rectHeight;
-        computeBounds(bounds, paint, left, top, offset, rectWidth, rectHeight);
-
-        if (!checkTextureSize(rectWidth, rectHeight)) return NULL;
-
-        purgeCache(rectWidth, rectHeight);
-
-        SkBitmap bitmap;
-        initBitmap(bitmap, rectWidth, rectHeight);
-
-        SkPaint pathPaint(*paint);
-        initPaint(pathPaint);
-
-        SkCanvas canvas(bitmap);
-        canvas.translate(-left + offset, -top + offset);
-        canvas.drawRect(bounds, pathPaint);
-
-        texture = createTexture(0, 0, offset, rectWidth, rectHeight, 0);
-        addTexture(entry, &bitmap, texture);
-    }
-
-    return texture;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Arcs
-///////////////////////////////////////////////////////////////////////////////
-
-ArcShapeCache::ArcShapeCache(): ShapeCache<ArcShapeCacheEntry>(
-        "arc", PROPERTY_SHAPE_CACHE_SIZE, DEFAULT_SHAPE_CACHE_SIZE) {
-}
-
-PathTexture* ArcShapeCache::getArc(float width, float height,
-        float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
-    ArcShapeCacheEntry entry(width, height, startAngle, sweepAngle, useCenter, paint);
-    PathTexture* texture = get(entry);
-
-    if (!texture) {
-        SkPath path;
-        SkRect r;
-        r.set(0.0f, 0.0f, width, height);
-        if (useCenter) {
-            path.moveTo(r.centerX(), r.centerY());
-        }
-        path.arcTo(r, startAngle, sweepAngle, !useCenter);
-        if (useCenter) {
-            path.close();
-        }
-
-        texture = addTexture(entry, &path, paint);
-    }
-
-    return texture;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
deleted file mode 100644
index 47cab83e..0000000
--- a/libs/hwui/ShapeCache.h
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
- * Copyright (C) 2011 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_SHAPE_CACHE_H
-#define ANDROID_HWUI_SHAPE_CACHE_H
-
-#include <GLES2/gl2.h>
-
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkPaint.h>
-#include <SkPath.h>
-#include <SkRect.h>
-
-#include <utils/JenkinsHash.h>
-#include <utils/LruCache.h>
-
-#include "Debug.h"
-#include "Properties.h"
-#include "Texture.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Defines
-///////////////////////////////////////////////////////////////////////////////
-
-// Debug
-#if DEBUG_SHAPES
-    #define SHAPE_LOGD(...) ALOGD(__VA_ARGS__)
-#else
-    #define SHAPE_LOGD(...)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// Classes
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Alpha texture used to represent a path.
- */
-struct PathTexture: public Texture {
-    PathTexture(): Texture() {
-    }
-
-    /**
-     * Left coordinate of the path bounds.
-     */
-    float left;
-    /**
-     * Top coordinate of the path bounds.
-     */
-    float top;
-    /**
-     * Offset to draw the path at the correct origin.
-     */
-    float offset;
-}; // struct PathTexture
-
-/**
- * Describe a shape in the shape cache.
- */
-struct ShapeCacheEntry {
-    enum ShapeType {
-        kShapeNone,
-        kShapeRect,
-        kShapeRoundRect,
-        kShapeCircle,
-        kShapeOval,
-        kShapeArc,
-        kShapePath
-    };
-
-    ShapeCacheEntry() {
-        shapeType = kShapeNone;
-        join = SkPaint::kDefault_Join;
-        cap = SkPaint::kDefault_Cap;
-        style = SkPaint::kFill_Style;
-        miter = 4.0f;
-        strokeWidth = 1.0f;
-        pathEffect = NULL;
-    }
-
-    ShapeCacheEntry(ShapeType type, SkPaint* paint) {
-        shapeType = type;
-        join = paint->getStrokeJoin();
-        cap = paint->getStrokeCap();
-        miter = paint->getStrokeMiter();
-        strokeWidth = paint->getStrokeWidth();
-        style = paint->getStyle();
-        pathEffect = paint->getPathEffect();
-    }
-
-    virtual ~ShapeCacheEntry() {
-    }
-
-    virtual hash_t hash() const {
-        uint32_t hash = JenkinsHashMix(0, shapeType);
-        hash = JenkinsHashMix(hash, join);
-        hash = JenkinsHashMix(hash, cap);
-        hash = JenkinsHashMix(hash, style);
-        hash = JenkinsHashMix(hash, android::hash_type(miter));
-        hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
-        hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
-        return JenkinsHashWhiten(hash);
-    }
-
-    virtual int compare(const ShapeCacheEntry& rhs) const {
-        int deltaInt = shapeType - rhs.shapeType;
-        if (deltaInt != 0) return deltaInt;
-
-        deltaInt = join - rhs.join;
-        if (deltaInt != 0) return deltaInt;
-
-        deltaInt = cap - rhs.cap;
-        if (deltaInt != 0) return deltaInt;
-
-        deltaInt = style - rhs.style;
-        if (deltaInt != 0) return deltaInt;
-
-        if (miter < rhs.miter) return -1;
-        if (miter > rhs.miter) return +1;
-
-        if (strokeWidth < rhs.strokeWidth) return -1;
-        if (strokeWidth > rhs.strokeWidth) return +1;
-
-        if (pathEffect < rhs.pathEffect) return -1;
-        if (pathEffect > rhs.pathEffect) return +1;
-
-        return 0;
-    }
-
-    bool operator==(const ShapeCacheEntry& other) const {
-        return compare(other) == 0;
-    }
-
-    bool operator!=(const ShapeCacheEntry& other) const {
-        return compare(other) != 0;
-    }
-
-    ShapeType shapeType;
-    SkPaint::Join join;
-    SkPaint::Cap cap;
-    SkPaint::Style style;
-    float miter;
-    float strokeWidth;
-    SkPathEffect* pathEffect;
-}; // struct ShapeCacheEntry
-
-// Cache support
-
-inline int strictly_order_type(const ShapeCacheEntry& lhs, const ShapeCacheEntry& rhs) {
-    return lhs.compare(rhs) < 0;
-}
-
-inline int compare_type(const ShapeCacheEntry& lhs, const ShapeCacheEntry& rhs) {
-    return lhs.compare(rhs);
-}
-
-inline hash_t hash_type(const ShapeCacheEntry& entry) {
-    return entry.hash();
-}
-
-struct RoundRectShapeCacheEntry: public ShapeCacheEntry {
-    RoundRectShapeCacheEntry(float width, float height, float rx, float ry, SkPaint* paint):
-            ShapeCacheEntry(ShapeCacheEntry::kShapeRoundRect, paint) {
-        mWidth = width;
-        mHeight = height;
-        mRx = rx;
-        mRy = ry;
-    }
-
-    RoundRectShapeCacheEntry(): ShapeCacheEntry() {
-        mWidth = 0;
-        mHeight = 0;
-        mRx = 0;
-        mRy = 0;
-    }
-
-    hash_t hash() const {
-        uint32_t hash = ShapeCacheEntry::hash();
-        hash = JenkinsHashMix(hash, android::hash_type(mWidth));
-        hash = JenkinsHashMix(hash, android::hash_type(mHeight));
-        hash = JenkinsHashMix(hash, android::hash_type(mRx));
-        hash = JenkinsHashMix(hash, android::hash_type(mRy));
-        return JenkinsHashWhiten(hash);
-    }
-
-    int compare(const ShapeCacheEntry& r) const {
-        int deltaInt = ShapeCacheEntry::compare(r);
-        if (deltaInt != 0) return deltaInt;
-
-        const RoundRectShapeCacheEntry& rhs = (const RoundRectShapeCacheEntry&) r;
-
-        if (mWidth < rhs.mWidth) return -1;
-        if (mWidth > rhs.mWidth) return +1;
-
-        if (mHeight < rhs.mHeight) return -1;
-        if (mHeight > rhs.mHeight) return +1;
-
-        if (mRx < rhs.mRx) return -1;
-        if (mRx > rhs.mRx) return +1;
-
-        if (mRy < rhs.mRy) return -1;
-        if (mRy > rhs.mRy) return +1;
-
-        return 0;
-    }
-
-private:
-    float mWidth;
-    float mHeight;
-    float mRx;
-    float mRy;
-}; // RoundRectShapeCacheEntry
-
-inline hash_t hash_type(const RoundRectShapeCacheEntry& entry) {
-    return entry.hash();
-}
-
-struct CircleShapeCacheEntry: public ShapeCacheEntry {
-    CircleShapeCacheEntry(float radius, SkPaint* paint):
-            ShapeCacheEntry(ShapeCacheEntry::kShapeCircle, paint) {
-        mRadius = radius;
-    }
-
-    CircleShapeCacheEntry(): ShapeCacheEntry() {
-        mRadius = 0;
-    }
-
-    hash_t hash() const {
-        uint32_t hash = ShapeCacheEntry::hash();
-        hash = JenkinsHashMix(hash, android::hash_type(mRadius));
-        return JenkinsHashWhiten(hash);
-    }
-
-    int compare(const ShapeCacheEntry& r) const {
-        int deltaInt = ShapeCacheEntry::compare(r);
-        if (deltaInt != 0) return deltaInt;
-
-        const CircleShapeCacheEntry& rhs = (const CircleShapeCacheEntry&) r;
-
-        if (mRadius < rhs.mRadius) return -1;
-        if (mRadius > rhs.mRadius) return +1;
-
-        return 0;
-    }
-
-private:
-    float mRadius;
-}; // CircleShapeCacheEntry
-
-inline hash_t hash_type(const CircleShapeCacheEntry& entry) {
-    return entry.hash();
-}
-
-struct OvalShapeCacheEntry: public ShapeCacheEntry {
-    OvalShapeCacheEntry(float width, float height, SkPaint* paint):
-            ShapeCacheEntry(ShapeCacheEntry::kShapeOval, paint) {
-        mWidth = width;
-        mHeight = height;
-    }
-
-    OvalShapeCacheEntry(): ShapeCacheEntry() {
-        mWidth = mHeight = 0;
-    }
-
-    hash_t hash() const {
-        uint32_t hash = ShapeCacheEntry::hash();
-        hash = JenkinsHashMix(hash, android::hash_type(mWidth));
-        hash = JenkinsHashMix(hash, android::hash_type(mHeight));
-        return JenkinsHashWhiten(hash);
-    }
-
-    int compare(const ShapeCacheEntry& r) const {
-        int deltaInt = ShapeCacheEntry::compare(r);
-        if (deltaInt != 0) return deltaInt;
-
-        const OvalShapeCacheEntry& rhs = (const OvalShapeCacheEntry&) r;
-
-        if (mWidth < rhs.mWidth) return -1;
-        if (mWidth > rhs.mWidth) return +1;
-
-        if (mHeight < rhs.mHeight) return -1;
-        if (mHeight > rhs.mHeight) return +1;
-
-        return 0;
-    }
-
-private:
-    float mWidth;
-    float mHeight;
-}; // OvalShapeCacheEntry
-
-inline hash_t hash_type(const OvalShapeCacheEntry& entry) {
-    return entry.hash();
-}
-
-struct RectShapeCacheEntry: public ShapeCacheEntry {
-    RectShapeCacheEntry(float width, float height, SkPaint* paint):
-            ShapeCacheEntry(ShapeCacheEntry::kShapeRect, paint) {
-        mWidth = width;
-        mHeight = height;
-    }
-
-    RectShapeCacheEntry(): ShapeCacheEntry() {
-        mWidth = mHeight = 0;
-    }
-
-    hash_t hash() const {
-        uint32_t hash = ShapeCacheEntry::hash();
-        hash = JenkinsHashMix(hash, android::hash_type(mWidth));
-        hash = JenkinsHashMix(hash, android::hash_type(mHeight));
-        return JenkinsHashWhiten(hash);
-    }
-
-    int compare(const ShapeCacheEntry& r) const {
-        int deltaInt = ShapeCacheEntry::compare(r);
-        if (deltaInt != 0) return deltaInt;
-
-        const RectShapeCacheEntry& rhs = (const RectShapeCacheEntry&) r;
-
-        if (mWidth < rhs.mWidth) return -1;
-        if (mWidth > rhs.mWidth) return +1;
-
-        if (mHeight < rhs.mHeight) return -1;
-        if (mHeight > rhs.mHeight) return +1;
-
-        return 0;
-    }
-
-private:
-    float mWidth;
-    float mHeight;
-}; // RectShapeCacheEntry
-
-inline hash_t hash_type(const RectShapeCacheEntry& entry) {
-    return entry.hash();
-}
-
-struct ArcShapeCacheEntry: public ShapeCacheEntry {
-    ArcShapeCacheEntry(float width, float height, float startAngle, float sweepAngle,
-            bool useCenter, SkPaint* paint):
-            ShapeCacheEntry(ShapeCacheEntry::kShapeArc, paint) {
-        mWidth = width;
-        mHeight = height;
-        mStartAngle = startAngle;
-        mSweepAngle = sweepAngle;
-        mUseCenter = useCenter ? 1 : 0;
-    }
-
-    ArcShapeCacheEntry(): ShapeCacheEntry() {
-        mWidth = 0;
-        mHeight = 0;
-        mStartAngle = 0;
-        mSweepAngle = 0;
-        mUseCenter = 0;
-    }
-
-    hash_t hash() const {
-        uint32_t hash = ShapeCacheEntry::hash();
-        hash = JenkinsHashMix(hash, android::hash_type(mWidth));
-        hash = JenkinsHashMix(hash, android::hash_type(mHeight));
-        hash = JenkinsHashMix(hash, android::hash_type(mStartAngle));
-        hash = JenkinsHashMix(hash, android::hash_type(mSweepAngle));
-        hash = JenkinsHashMix(hash, mUseCenter);
-        return JenkinsHashWhiten(hash);
-    }
-
-    int compare(const ShapeCacheEntry& r) const {
-        int deltaInt = ShapeCacheEntry::compare(r);
-        if (deltaInt != 0) return deltaInt;
-
-        const ArcShapeCacheEntry& rhs = (const ArcShapeCacheEntry&) r;
-
-        if (mWidth < rhs.mWidth) return -1;
-        if (mWidth > rhs.mWidth) return +1;
-
-        if (mHeight < rhs.mHeight) return -1;
-        if (mHeight > rhs.mHeight) return +1;
-
-        if (mStartAngle < rhs.mStartAngle) return -1;
-        if (mStartAngle > rhs.mStartAngle) return +1;
-
-        if (mSweepAngle < rhs.mSweepAngle) return -1;
-        if (mSweepAngle > rhs.mSweepAngle) return +1;
-
-        return mUseCenter - rhs.mUseCenter;
-    }
-
-private:
-    float mWidth;
-    float mHeight;
-    float mStartAngle;
-    float mSweepAngle;
-    uint32_t mUseCenter;
-}; // ArcShapeCacheEntry
-
-inline hash_t hash_type(const ArcShapeCacheEntry& entry) {
-    return entry.hash();
-}
-
-/**
- * A simple LRU shape cache. The cache has a maximum size expressed in bytes.
- * Any texture added to the cache causing the cache to grow beyond the maximum
- * allowed size will also cause the oldest texture to be kicked out.
- */
-template<typename Entry>
-class ShapeCache: public OnEntryRemoved<Entry, PathTexture*> {
-public:
-    ShapeCache(const char* name, const char* propertyName, float defaultSize);
-    ~ShapeCache();
-
-    /**
-     * Used as a callback when an entry is removed from the cache.
-     * Do not invoke directly.
-     */
-    void operator()(Entry& path, PathTexture*& texture);
-
-    /**
-     * Clears the cache. This causes all textures to be deleted.
-     */
-    void clear();
-
-    /**
-     * Sets the maximum size of the cache in bytes.
-     */
-    void setMaxSize(uint32_t maxSize);
-    /**
-     * Returns the maximum size of the cache in bytes.
-     */
-    uint32_t getMaxSize();
-    /**
-     * Returns the current size of the cache in bytes.
-     */
-    uint32_t getSize();
-
-protected:
-    PathTexture* addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint);
-    PathTexture* addTexture(const Entry& entry, SkBitmap* bitmap);
-    void addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture);
-
-    /**
-     * Ensures there is enough space in the cache for a texture of the specified
-     * dimensions.
-     */
-    void purgeCache(uint32_t width, uint32_t height);
-
-    void initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height);
-    void initPaint(SkPaint& paint);
-
-    bool checkTextureSize(uint32_t width, uint32_t height);
-
-    PathTexture* get(Entry entry) {
-        return mCache.get(entry);
-    }
-
-    void removeTexture(PathTexture* texture);
-
-    LruCache<Entry, PathTexture*> mCache;
-    uint32_t mSize;
-    uint32_t mMaxSize;
-    GLuint mMaxTextureSize;
-
-    char* mName;
-    bool mDebugEnabled;
-
-private:
-    /**
-     * Generates the texture from a bitmap into the specified texture structure.
-     */
-    void generateTexture(SkBitmap& bitmap, Texture* texture);
-
-    void init();
-}; // class ShapeCache
-
-class RoundRectShapeCache: public ShapeCache<RoundRectShapeCacheEntry> {
-public:
-    RoundRectShapeCache();
-
-    PathTexture* getRoundRect(float width, float height, float rx, float ry, SkPaint* paint);
-}; // class RoundRectShapeCache
-
-class CircleShapeCache: public ShapeCache<CircleShapeCacheEntry> {
-public:
-    CircleShapeCache();
-
-    PathTexture* getCircle(float radius, SkPaint* paint);
-}; // class CircleShapeCache
-
-class OvalShapeCache: public ShapeCache<OvalShapeCacheEntry> {
-public:
-    OvalShapeCache();
-
-    PathTexture* getOval(float width, float height, SkPaint* paint);
-}; // class OvalShapeCache
-
-class RectShapeCache: public ShapeCache<RectShapeCacheEntry> {
-public:
-    RectShapeCache();
-
-    PathTexture* getRect(float width, float height, SkPaint* paint);
-}; // class RectShapeCache
-
-class ArcShapeCache: public ShapeCache<ArcShapeCacheEntry> {
-public:
-    ArcShapeCache();
-
-    PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
-            bool useCenter, SkPaint* paint);
-}; // class ArcShapeCache
-
-///////////////////////////////////////////////////////////////////////////////
-// Constructors/destructor
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-ShapeCache<Entry>::ShapeCache(const char* name, const char* propertyName, float defaultSize):
-        mCache(LruCache<ShapeCacheEntry, PathTexture*>::kUnlimitedCapacity),
-        mSize(0), mMaxSize(MB(defaultSize)) {
-    char property[PROPERTY_VALUE_MAX];
-    if (property_get(propertyName, property, NULL) > 0) {
-        INIT_LOGD("  Setting %s cache size to %sMB", name, property);
-        setMaxSize(MB(atof(property)));
-    } else {
-        INIT_LOGD("  Using default %s cache size of %.2fMB", name, defaultSize);
-    }
-
-    size_t len = strlen(name);
-    mName = new char[len + 1];
-    strcpy(mName, name);
-    mName[len] = '\0';
-
-    init();
-}
-
-template<class Entry>
-ShapeCache<Entry>::~ShapeCache() {
-    mCache.clear();
-    delete[] mName;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::init() {
-    mCache.setOnEntryRemovedListener(this);
-
-    GLint maxTextureSize;
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
-    mMaxTextureSize = maxTextureSize;
-
-    mDebugEnabled = readDebugLevel() & kDebugCaches;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Size management
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-uint32_t ShapeCache<Entry>::getSize() {
-    return mSize;
-}
-
-template<class Entry>
-uint32_t ShapeCache<Entry>::getMaxSize() {
-    return mMaxSize;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::setMaxSize(uint32_t maxSize) {
-    mMaxSize = maxSize;
-    while (mSize > mMaxSize) {
-        mCache.removeOldest();
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Callbacks
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-void ShapeCache<Entry>::operator()(Entry& path, PathTexture*& texture) {
-    removeTexture(texture);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Caching
-///////////////////////////////////////////////////////////////////////////////
-
-template<class Entry>
-void ShapeCache<Entry>::removeTexture(PathTexture* texture) {
-    if (texture) {
-        const uint32_t size = texture->width * texture->height;
-        mSize -= size;
-
-        SHAPE_LOGD("ShapeCache::callback: delete %s: name, size, mSize = %d, %d, %d",
-                mName, texture->id, size, mSize);
-        if (mDebugEnabled) {
-            ALOGD("Shape %s deleted, size = %d", mName, size);
-        }
-
-        glDeleteTextures(1, &texture->id);
-        delete texture;
-    }
-}
-
-void computePathBounds(const SkPath* path, const SkPaint* paint,
-        float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
-void computeBounds(const SkRect& bounds, const SkPaint* paint,
-        float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
-
-static PathTexture* createTexture(float left, float top, float offset,
-        uint32_t width, uint32_t height, uint32_t id) {
-    PathTexture* texture = new PathTexture;
-    texture->left = left;
-    texture->top = top;
-    texture->offset = offset;
-    texture->width = width;
-    texture->height = height;
-    texture->generation = id;
-    return texture;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::purgeCache(uint32_t width, uint32_t height) {
-    const uint32_t size = width * height;
-    // Don't even try to cache a bitmap that's bigger than the cache
-    if (size < mMaxSize) {
-        while (mSize + size > mMaxSize) {
-            mCache.removeOldest();
-        }
-    }
-}
-
-template<class Entry>
-void ShapeCache<Entry>::initBitmap(SkBitmap& bitmap, uint32_t width, uint32_t height) {
-    bitmap.setConfig(SkBitmap::kA8_Config, width, height);
-    bitmap.allocPixels();
-    bitmap.eraseColor(0);
-}
-
-template<class Entry>
-void ShapeCache<Entry>::initPaint(SkPaint& paint) {
-    // Make sure the paint is opaque, color, alpha, filter, etc.
-    // will be applied later when compositing the alpha8 texture
-    paint.setColor(0xff000000);
-    paint.setAlpha(255);
-    paint.setColorFilter(NULL);
-    paint.setMaskFilter(NULL);
-    paint.setShader(NULL);
-    SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
-    SkSafeUnref(paint.setXfermode(mode));
-}
-
-template<class Entry>
-bool ShapeCache<Entry>::checkTextureSize(uint32_t width, uint32_t height) {
-    if (width > mMaxTextureSize || height > mMaxTextureSize) {
-        ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
-                mName, width, height, mMaxTextureSize, mMaxTextureSize);
-        return false;
-    }
-    return true;
-}
-
-template<class Entry>
-PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
-        const SkPaint* paint) {
-
-    float left, top, offset;
-    uint32_t width, height;
-    computePathBounds(path, paint, left, top, offset, width, height);
-
-    if (!checkTextureSize(width, height)) return NULL;
-
-    purgeCache(width, height);
-
-    SkBitmap bitmap;
-    initBitmap(bitmap, width, height);
-
-    SkPaint pathPaint(*paint);
-    initPaint(pathPaint);
-
-    SkCanvas canvas(bitmap);
-    canvas.translate(-left + offset, -top + offset);
-    canvas.drawPath(*path, pathPaint);
-
-    PathTexture* texture = createTexture(left, top, offset, width, height, path->getGenerationID());
-    addTexture(entry, &bitmap, texture);
-
-    return texture;
-}
-
-template<class Entry>
-void ShapeCache<Entry>::addTexture(const Entry& entry, SkBitmap* bitmap, PathTexture* texture) {
-    generateTexture(*bitmap, texture);
-
-    uint32_t size = texture->width * texture->height;
-    if (size < mMaxSize) {
-        mSize += size;
-        SHAPE_LOGD("ShapeCache::get: create %s: name, size, mSize = %d, %d, %d",
-                mName, texture->id, size, mSize);
-        if (mDebugEnabled) {
-            ALOGD("Shape %s created, size = %d", mName, size);
-        }
-        mCache.put(entry, texture);
-    } else {
-        texture->cleanup = true;
-    }
-}
-
-template<class Entry>
-void ShapeCache<Entry>::clear() {
-    mCache.clear();
-}
-
-template<class Entry>
-void ShapeCache<Entry>::generateTexture(SkBitmap& bitmap, Texture* texture) {
-    SkAutoLockPixels alp(bitmap);
-    if (!bitmap.readyToDraw()) {
-        ALOGE("Cannot generate texture from bitmap");
-        return;
-    }
-
-    glGenTextures(1, &texture->id);
-
-    glBindTexture(GL_TEXTURE_2D, texture->id);
-    // Textures are Alpha8
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
-    texture->blend = true;
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
-            GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels());
-
-    texture->setFilter(GL_LINEAR);
-    texture->setWrap(GL_CLAMP_TO_EDGE);
-}
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_SHAPE_CACHE_H
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 9013fd5..c38eedb 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -411,8 +411,14 @@
 
 void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
         const Snapshot& snapshot, GLuint* textureUnit) {
-    mFirst->setupProgram(program, modelView, snapshot, textureUnit);
-    mSecond->setupProgram(program, modelView, snapshot, textureUnit);
+    // Apply this compose shader's local transform and pass it down to
+    // the child shaders. They will in turn apply their local transform
+    // to this matrix.
+    mat4 transform;
+    computeScreenSpaceMatrix(transform, modelView);
+
+    mFirst->setupProgram(program, transform, snapshot, textureUnit);
+    mSecond->setupProgram(program, transform, snapshot, textureUnit);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 923913e..d26ee38 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "OpenGLRenderer"
+
 #include "Snapshot.h"
 
 #include <SkCanvas.h>
@@ -199,5 +201,14 @@
     return invisible || empty;
 }
 
+void Snapshot::dump() const {
+    ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
+            this, flags, previous.get(), height, isIgnored(), clipRegion && !clipRegion->isEmpty());
+    ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
+            clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+    ALOGD("  Transform (at %p):", transform);
+    transform->dump();
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index ffd4729..cc6d0cd 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -228,6 +228,8 @@
      */
     float alpha;
 
+    void dump() const;
+
 private:
     void ensureClipRegion();
     void copyClipRectFromRegion();
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 5cff5a5..2378eb5 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -20,7 +20,7 @@
 
 #include <SkCanvas.h>
 
-#include <utils/threads.h>
+#include <utils/Mutex.h>
 
 #include "Caches.h"
 #include "TextureCache.h"
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 24b0523..577f463 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -15,10 +15,9 @@
  */
 
 #include <SkGlyph.h>
-#include <utils/Log.h>
 
-#include "Debug.h"
 #include "CacheTexture.h"
+#include "../Debug.h"
 
 namespace android {
 namespace uirenderer {
@@ -106,6 +105,84 @@
 // CacheTexture
 ///////////////////////////////////////////////////////////////////////////////
 
+CacheTexture::CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount) :
+            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
+            mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
+            mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount) {
+    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+            mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
+}
+
+CacheTexture::~CacheTexture() {
+    releaseMesh();
+    releaseTexture();
+    reset();
+}
+
+void CacheTexture::reset() {
+    // Delete existing cache blocks
+    while (mCacheBlocks != NULL) {
+        CacheBlock* tmpBlock = mCacheBlocks;
+        mCacheBlocks = mCacheBlocks->mNext;
+        delete tmpBlock;
+    }
+    mNumGlyphs = 0;
+    mCurrentQuad = 0;
+}
+
+void CacheTexture::init() {
+    // reset, then create a new remainder space to start again
+    reset();
+    mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+            mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
+}
+
+void CacheTexture::releaseMesh() {
+    delete[] mMesh;
+}
+
+void CacheTexture::releaseTexture() {
+    if (mTexture) {
+        delete[] mTexture;
+        mTexture = NULL;
+    }
+    if (mTextureId) {
+        glDeleteTextures(1, &mTextureId);
+        mTextureId = 0;
+    }
+    mDirty = false;
+    mCurrentQuad = 0;
+}
+
+void CacheTexture::allocateMesh() {
+    if (!mMesh) {
+        mMesh = new TextureVertex[mMaxQuadCount * 4];
+    }
+}
+
+void CacheTexture::allocateTexture() {
+    if (!mTexture) {
+        mTexture = new uint8_t[mWidth * mHeight];
+    }
+
+    if (!mTextureId) {
+        glGenTextures(1, &mTextureId);
+
+        glBindTexture(GL_TEXTURE_2D, mTextureId);
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        // Initialize texture dimensions
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0,
+                GL_ALPHA, GL_UNSIGNED_BYTE, 0);
+
+        const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    }
+}
+
 bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
     if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mHeight) {
         return false;
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index fdd1623..e7fb474 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -17,14 +17,15 @@
 #ifndef ANDROID_HWUI_CACHE_TEXTURE_H
 #define ANDROID_HWUI_CACHE_TEXTURE_H
 
-#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
 
 #include <SkScalerContext.h>
 
 #include <utils/Log.h>
 
 #include "FontUtil.h"
-#include "Rect.h"
+#include "../Rect.h"
+#include "../Vertex.h"
 
 namespace android {
 namespace uirenderer {
@@ -55,14 +56,14 @@
     }
 
     static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
-
     static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
 
     void output() {
         CacheBlock* currBlock = this;
         while (currBlock) {
             ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
-                    currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight);
+                    currBlock, currBlock->mX, currBlock->mY,
+                    currBlock->mWidth, currBlock->mHeight);
             currBlock = currBlock->mNext;
         }
     }
@@ -70,72 +71,17 @@
 
 class CacheTexture {
 public:
-    CacheTexture(uint16_t width, uint16_t height) :
-            mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
-            mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
-        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
-                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
-    }
+    CacheTexture(uint16_t width, uint16_t height, uint32_t maxQuadCount);
+    ~CacheTexture();
 
-    ~CacheTexture() {
-        releaseTexture();
-        reset();
-    }
+    void reset();
+    void init();
 
-    void reset() {
-        // Delete existing cache blocks
-        while (mCacheBlocks != NULL) {
-            CacheBlock* tmpBlock = mCacheBlocks;
-            mCacheBlocks = mCacheBlocks->mNext;
-            delete tmpBlock;
-        }
-        mNumGlyphs = 0;
-    }
+    void releaseMesh();
+    void releaseTexture();
 
-    void init() {
-        // reset, then create a new remainder space to start again
-        reset();
-        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
-                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
-    }
-
-    void releaseTexture() {
-        if (mTexture) {
-            delete[] mTexture;
-            mTexture = NULL;
-        }
-        if (mTextureId) {
-            glDeleteTextures(1, &mTextureId);
-            mTextureId = 0;
-        }
-        mDirty = false;
-    }
-
-    /**
-     * This method assumes that the proper texture unit is active.
-     */
-    void allocateTexture() {
-        if (!mTexture) {
-            mTexture = new uint8_t[mWidth * mHeight];
-        }
-
-        if (!mTextureId) {
-            glGenTextures(1, &mTextureId);
-
-            glBindTexture(GL_TEXTURE_2D, mTextureId);
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-            // Initialize texture dimensions
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mWidth, mHeight, 0,
-                    GL_ALPHA, GL_UNSIGNED_BYTE, 0);
-
-            const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
-
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-        }
-    }
+    void allocateTexture();
+    void allocateMesh();
 
     bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
 
@@ -193,6 +139,42 @@
         return mNumGlyphs;
     }
 
+    TextureVertex* mesh() const {
+        return mMesh;
+    }
+
+    uint32_t meshElementCount() const {
+        return mCurrentQuad * 6;
+    }
+
+    uint16_t* indices() const {
+        return (uint16_t*) 0;
+    }
+
+    void resetMesh() {
+        mCurrentQuad = 0;
+    }
+
+    inline void addQuad(float x1, float y1, float u1, float v1,
+            float x2, float y2, float u2, float v2,
+            float x3, float y3, float u3, float v3,
+            float x4, float y4, float u4, float v4) {
+        TextureVertex* mesh = mMesh + mCurrentQuad * 4;
+        TextureVertex::set(mesh++, x1, y1, u1, v1);
+        TextureVertex::set(mesh++, x2, y2, u2, v2);
+        TextureVertex::set(mesh++, x3, y3, u3, v3);
+        TextureVertex::set(mesh++, x4, y4, u4, v4);
+        mCurrentQuad++;
+    }
+
+    bool canDraw() const {
+        return mCurrentQuad > 0;
+    }
+
+    bool endOfMesh() const {
+        return mCurrentQuad == mMaxQuadCount;
+    }
+
 private:
     uint8_t* mTexture;
     GLuint mTextureId;
@@ -201,6 +183,9 @@
     bool mLinearFiltering;
     bool mDirty;
     uint16_t mNumGlyphs;
+    TextureVertex* mMesh;
+    uint32_t mCurrentQuad;
+    uint32_t mMaxQuadCount;
     CacheBlock* mCacheBlocks;
     Rect mDirtyRect;
 };
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 9307f11..02c1aa1 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -15,10 +15,12 @@
  */
 
 #define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
 
 #include <cutils/compiler.h>
 
 #include <utils/JenkinsHash.h>
+#include <utils/Trace.h>
 
 #include <SkGlyph.h>
 #include <SkUtils.h>
@@ -53,8 +55,8 @@
     mStrokeWidth = paint->getStrokeWidth();
     mAntiAliasing = paint->isAntiAlias();
     mLookupTransform.reset();
-    mLookupTransform[SkMatrix::kMScaleX] = matrix[mat4::kScaleX];
-    mLookupTransform[SkMatrix::kMScaleY] = matrix[mat4::kScaleY];
+    mLookupTransform[SkMatrix::kMScaleX] = roundf(fmaxf(1.0f, matrix[mat4::kScaleX]));
+    mLookupTransform[SkMatrix::kMScaleY] = roundf(fmaxf(1.0f, matrix[mat4::kScaleY]));
     if (!mLookupTransform.invert(&mInverseLookupTransform)) {
         ALOGW("Could not query the inverse lookup transform for this font");
     }
@@ -261,11 +263,8 @@
 }
 
 CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) {
-    CachedGlyphInfo* cachedGlyph = NULL;
-    ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
-    if (index >= 0) {
-        cachedGlyph = mCachedGlyphs.valueAt(index);
-
+    CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueFor(textUnit);
+    if (cachedGlyph) {
         // Is the glyph still in texture cache?
         if (!cachedGlyph->mIsValid) {
             const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit,
@@ -346,11 +345,13 @@
 }
 
 void Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
+    ATRACE_NAME("precacheText");
+
     if (numGlyphs == 0 || text == NULL) {
         return;
     }
-    int glyphsCount = 0;
 
+    int glyphsCount = 0;
     while (glyphsCount < numGlyphs) {
         glyph_t glyph = GET_GLYPH(text);
 
@@ -360,7 +361,6 @@
         }
 
         CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true);
-
         glyphsCount++;
     }
 }
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index 4f9c46b..f758666 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -26,7 +26,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024
-#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 256
+#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 512
 #define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048
 #define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512
 
diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h
new file mode 100644
index 0000000..6cb23e5
--- /dev/null
+++ b/libs/hwui/thread/Barrier.h
@@ -0,0 +1,58 @@
+/*
+ * 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_BARRIER_H
+#define ANDROID_HWUI_BARRIER_H
+
+#include <utils/Condition.h>
+
+namespace android {
+namespace uirenderer {
+
+class Barrier {
+public:
+    Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mOpened(false) { }
+    ~Barrier() { }
+
+    void open() {
+        Mutex::Autolock l(mLock);
+        mOpened = true;
+        mCondition.signal(mType);
+    }
+
+    void close() {
+        Mutex::Autolock l(mLock);
+        mOpened = false;
+    }
+
+    void wait() const {
+        Mutex::Autolock l(mLock);
+        while (!mOpened) {
+            mCondition.wait(mLock);
+        }
+    }
+
+private:
+    Condition::WakeUpType mType;
+    volatile bool mOpened;
+    mutable Mutex mLock;
+    mutable Condition mCondition;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_BARRIER_H
diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h
new file mode 100644
index 0000000..a3ff3bc
--- /dev/null
+++ b/libs/hwui/thread/Future.h
@@ -0,0 +1,58 @@
+/*
+ * 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_FUTURE_H
+#define ANDROID_HWUI_FUTURE_H
+
+#include <utils/RefBase.h>
+
+#include "Barrier.h"
+
+namespace android {
+namespace uirenderer {
+
+template<typename T>
+class Future: public LightRefBase<Future<T> > {
+public:
+    Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE): mBarrier(type), mResult() { }
+    ~Future() { }
+
+    /**
+     * Returns the result of this future, blocking if
+     * the result is not available yet.
+     */
+    T get() const {
+        mBarrier.wait();
+        return mResult;
+    }
+
+    /**
+     * This method must be called only once.
+     */
+    void produce(T result) {
+        mResult = result;
+        mBarrier.open();
+    }
+
+private:
+    Barrier mBarrier;
+    T mResult;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_FUTURE_H
diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h
new file mode 100644
index 0000000..dcf5449
--- /dev/null
+++ b/libs/hwui/thread/Signal.h
@@ -0,0 +1,56 @@
+/*
+ * 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_SIGNAL_H
+#define ANDROID_HWUI_SIGNAL_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/threads.h>
+
+namespace android {
+namespace uirenderer {
+
+class Signal {
+public:
+    Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mSignaled(false) { }
+    ~Signal() { }
+
+    void signal() {
+        Mutex::Autolock l(mLock);
+        mSignaled = true;
+        mCondition.signal(mType);
+    }
+
+    void wait() {
+        Mutex::Autolock l(mLock);
+        while (!mSignaled) {
+            mCondition.wait(mLock);
+        }
+        mSignaled = false;
+    }
+
+private:
+    Condition::WakeUpType mType;
+    volatile bool mSignaled;
+    mutable Mutex mLock;
+    mutable Condition mCondition;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_SIGNAL_H
diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h
new file mode 100644
index 0000000..9a211a2
--- /dev/null
+++ b/libs/hwui/thread/Task.h
@@ -0,0 +1,63 @@
+/*
+ * 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_TASK_H
+#define ANDROID_HWUI_TASK_H
+
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <utils/RefBase.h>
+#include <utils/Trace.h>
+
+#include "Future.h"
+
+namespace android {
+namespace uirenderer {
+
+class TaskBase: public RefBase {
+public:
+    TaskBase() { }
+    virtual ~TaskBase() { }
+};
+
+template<typename T>
+class Task: public TaskBase {
+public:
+    Task(): mFuture(new Future<T>()) { }
+    virtual ~Task() { }
+
+    T getResult() const {
+        ATRACE_NAME("waitForTask");
+        return mFuture->get();
+    }
+
+    void setResult(T result) {
+        mFuture->produce(result);
+    }
+
+protected:
+    const sp<Future<T> >& future() const {
+        return mFuture;
+    }
+
+private:
+    sp<Future<T> > mFuture;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TASK_H
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
new file mode 100644
index 0000000..c8bfd9c
--- /dev/null
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+
+#include <sys/sysinfo.h>
+
+#include "Task.h"
+#include "TaskProcessor.h"
+#include "TaskManager.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Manager
+///////////////////////////////////////////////////////////////////////////////
+
+TaskManager::TaskManager() {
+    // Get the number of available CPUs. This value does not change over time.
+    int cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
+
+    for (int i = 0; i < cpuCount / 2; i++) {
+        String8 name;
+        name.appendFormat("hwuiTask%d", i + 1);
+        mThreads.add(new WorkerThread(name));
+    }
+}
+
+TaskManager::~TaskManager() {
+    for (size_t i = 0; i < mThreads.size(); i++) {
+        mThreads[i]->exit();
+    }
+}
+
+bool TaskManager::canRunTasks() const {
+    return mThreads.size() > 0;
+}
+
+void TaskManager::stop() {
+    for (size_t i = 0; i < mThreads.size(); i++) {
+        mThreads[i]->exit();
+    }
+}
+
+bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
+    if (mThreads.size() > 0) {
+        TaskWrapper wrapper(task, processor);
+
+        size_t minQueueSize = INT_MAX;
+        sp<WorkerThread> thread;
+
+        for (size_t i = 0; i < mThreads.size(); i++) {
+            if (mThreads[i]->getTaskCount() < minQueueSize) {
+                thread = mThreads[i];
+                minQueueSize = mThreads[i]->getTaskCount();
+            }
+        }
+
+        return thread->addTask(wrapper);
+    }
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Thread
+///////////////////////////////////////////////////////////////////////////////
+
+bool TaskManager::WorkerThread::threadLoop() {
+    mSignal.wait();
+    Vector<TaskWrapper> tasks;
+    {
+        Mutex::Autolock l(mLock);
+        tasks = mTasks;
+        mTasks.clear();
+    }
+
+    for (size_t i = 0; i < tasks.size(); i++) {
+        const TaskWrapper& task = tasks.itemAt(i);
+        task.mProcessor->process(task.mTask);
+    }
+
+    return true;
+}
+
+bool TaskManager::WorkerThread::addTask(TaskWrapper task) {
+    if (!isRunning()) {
+        run(mName.string(), PRIORITY_DEFAULT);
+    }
+
+    Mutex::Autolock l(mLock);
+    ssize_t index = mTasks.add(task);
+    mSignal.signal();
+
+    return index >= 0;
+}
+
+size_t TaskManager::WorkerThread::getTaskCount() const {
+    Mutex::Autolock l(mLock);
+    return mTasks.size();
+}
+
+void TaskManager::WorkerThread::exit() {
+    {
+        Mutex::Autolock l(mLock);
+        mTasks.clear();
+    }
+    requestExit();
+    mSignal.signal();
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
new file mode 100644
index 0000000..477314b
--- /dev/null
+++ b/libs/hwui/thread/TaskManager.h
@@ -0,0 +1,106 @@
+/*
+ * 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_TASK_MANAGER_H
+#define ANDROID_HWUI_TASK_MANAGER_H
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Vector.h>
+
+#include "Signal.h"
+
+namespace android {
+namespace uirenderer {
+
+template <typename T>
+class Task;
+class TaskBase;
+
+template <typename T>
+class TaskProcessor;
+class TaskProcessorBase;
+
+class TaskManager {
+public:
+    TaskManager();
+    ~TaskManager();
+
+    /**
+     * Returns true if this task  manager can run tasks,
+     * false otherwise. This method will typically return
+     * true on a single CPU core device.
+     */
+    bool canRunTasks() const;
+
+    /**
+     * Stops all allocated threads. Adding tasks will start
+     * the threads again as necessary.
+     */
+    void stop();
+
+private:
+    template <typename T>
+    friend class TaskProcessor;
+
+    template<typename T>
+    bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
+        return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
+    }
+
+    bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
+
+    struct TaskWrapper {
+        TaskWrapper(): mTask(), mProcessor() { }
+
+        TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor):
+            mTask(task), mProcessor(processor) {
+        }
+
+        sp<TaskBase> mTask;
+        sp<TaskProcessorBase> mProcessor;
+    };
+
+    class WorkerThread: public Thread {
+    public:
+        WorkerThread(const String8 name): mSignal(Condition::WAKE_UP_ONE), mName(name) { }
+
+        bool addTask(TaskWrapper task);
+        size_t getTaskCount() const;
+        void exit();
+
+    private:
+        virtual bool threadLoop();
+
+        // Lock for the list of tasks
+        mutable Mutex mLock;
+        Vector<TaskWrapper> mTasks;
+
+        // Signal used to wake up the thread when a new
+        // task is available in the list
+        mutable Signal mSignal;
+
+        const String8 mName;
+    };
+
+    Vector<sp<WorkerThread> > mThreads;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TASK_MANAGER_H
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
new file mode 100644
index 0000000..d1269f0
--- /dev/null
+++ b/libs/hwui/thread/TaskProcessor.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_TASK_PROCESSOR_H
+#define ANDROID_HWUI_TASK_PROCESSOR_H
+
+#include <utils/RefBase.h>
+
+#include "Task.h"
+#include "TaskManager.h"
+
+namespace android {
+namespace uirenderer {
+
+class TaskProcessorBase: public RefBase {
+public:
+    TaskProcessorBase() { }
+    virtual ~TaskProcessorBase() { };
+
+private:
+    friend class TaskManager;
+
+    virtual void process(const sp<TaskBase>& task) = 0;
+};
+
+template<typename T>
+class TaskProcessor: public TaskProcessorBase {
+public:
+    TaskProcessor(TaskManager* manager): mManager(manager) { }
+    virtual ~TaskProcessor() { }
+
+    bool add(const sp<Task<T> >& task);
+
+    virtual void onProcess(const sp<Task<T> >& task) = 0;
+
+private:
+    virtual void process(const sp<TaskBase>& task) {
+        sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
+        // This is the right way to do it but sp<> doesn't play nice
+        // sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
+        onProcess(realTask);
+    }
+
+    TaskManager* mManager;
+};
+
+template<typename T>
+bool TaskProcessor<T>::add(const sp<Task<T> >& task) {
+    if (mManager) {
+        sp<TaskProcessor<T> > self(this);
+        return mManager->addTask(task, self);
+    }
+    return false;
+}
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_TASK_PROCESSOR_H
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
new file mode 100644
index 0000000..85d90d0
--- /dev/null
+++ b/libs/hwui/utils/Blur.cpp
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <math.h>
+
+#include "Blur.h"
+
+namespace android {
+namespace uirenderer {
+
+void Blur::generateGaussianWeights(float* weights, int32_t radius) {
+    // Compute gaussian weights for the blur
+    // e is the euler's number
+    static float e = 2.718281828459045f;
+    static float pi = 3.1415926535897932f;
+    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
+    // x is of the form [-radius .. 0 .. radius]
+    // and sigma varies with radius.
+    // Based on some experimental radius values and sigma's
+    // we approximately fit sigma = f(radius) as
+    // sigma = radius * 0.3  + 0.6
+    // The larger the radius gets, the more our gaussian blur
+    // will resemble a box blur since with large sigma
+    // the gaussian curve begins to lose its shape
+    float sigma = 0.3f * (float) radius + 0.6f;
+
+    // Now compute the coefficints
+    // We will store some redundant values to save some math during
+    // the blur calculations
+    // precompute some values
+    float coeff1 = 1.0f / (sqrt(2.0f * pi) * sigma);
+    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+
+    float normalizeFactor = 0.0f;
+    for (int32_t r = -radius; r <= radius; r ++) {
+        float floatR = (float) r;
+        weights[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
+        normalizeFactor += weights[r + radius];
+    }
+
+    //Now we need to normalize the weights because all our coefficients need to add up to one
+    normalizeFactor = 1.0f / normalizeFactor;
+    for (int32_t r = -radius; r <= radius; r ++) {
+        weights[r + radius] *= normalizeFactor;
+    }
+}
+
+void Blur::horizontal(float* weights, int32_t radius,
+        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
+    float blurredPixel = 0.0f;
+    float currentPixel = 0.0f;
+
+    for (int32_t y = 0; y < height; y ++) {
+
+        const uint8_t* input = source + y * width;
+        uint8_t* output = dest + y * width;
+
+        for (int32_t x = 0; x < width; x ++) {
+            blurredPixel = 0.0f;
+            const float* gPtr = weights;
+            // Optimization for non-border pixels
+            if (x > radius && x < (width - radius)) {
+                const uint8_t *i = input + (x - radius);
+                for (int r = -radius; r <= radius; r ++) {
+                    currentPixel = (float) (*i);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                    i++;
+                }
+            } else {
+                for (int32_t r = -radius; r <= radius; r ++) {
+                    // Stepping left and right away from the pixel
+                    int validW = x + r;
+                    if (validW < 0) {
+                        validW = 0;
+                    }
+                    if (validW > width - 1) {
+                        validW = width - 1;
+                    }
+
+                    currentPixel = (float) input[validW];
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                }
+            }
+            *output = (uint8_t)blurredPixel;
+            output ++;
+        }
+    }
+}
+
+void Blur::vertical(float* weights, int32_t radius,
+        const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
+    float blurredPixel = 0.0f;
+    float currentPixel = 0.0f;
+
+    for (int32_t y = 0; y < height; y ++) {
+        uint8_t* output = dest + y * width;
+
+        for (int32_t x = 0; x < width; x ++) {
+            blurredPixel = 0.0f;
+            const float* gPtr = weights;
+            const uint8_t* input = source + x;
+            // Optimization for non-border pixels
+            if (y > radius && y < (height - radius)) {
+                const uint8_t *i = input + ((y - radius) * width);
+                for (int32_t r = -radius; r <= radius; r ++) {
+                    currentPixel = (float) (*i);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                    i += width;
+                }
+            } else {
+                for (int32_t r = -radius; r <= radius; r ++) {
+                    int validH = y + r;
+                    // Clamp to zero and width
+                    if (validH < 0) {
+                        validH = 0;
+                    }
+                    if (validH > height - 1) {
+                        validH = height - 1;
+                    }
+
+                    const uint8_t *i = input + validH * width;
+                    currentPixel = (float) (*i);
+                    blurredPixel += currentPixel * gPtr[0];
+                    gPtr++;
+                }
+            }
+            *output = (uint8_t) blurredPixel;
+            output++;
+        }
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
new file mode 100644
index 0000000..6c176e9
--- /dev/null
+++ b/libs/hwui/utils/Blur.h
@@ -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.
+ */
+
+#ifndef ANDROID_HWUI_BLUR_H
+#define ANDROID_HWUI_BLUR_H
+
+#include <stdint.h>
+
+namespace android {
+namespace uirenderer {
+
+class Blur {
+public:
+    static void generateGaussianWeights(float* weights, int32_t radius);
+    static void horizontal(float* weights, int32_t radius, const uint8_t* source,
+        uint8_t* dest, int32_t width, int32_t height);
+    static void vertical(float* weights, int32_t radius, const uint8_t* source,
+        uint8_t* dest, int32_t width, int32_t height);
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_BLUR_H
diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h
new file mode 100644
index 0000000..172606a
--- /dev/null
+++ b/libs/hwui/utils/Pair.h
@@ -0,0 +1,58 @@
+/*
+ * 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_PAIR_H
+#define ANDROID_HWUI_PAIR_H
+
+namespace android {
+namespace uirenderer {
+
+template <typename F, typename S>
+struct Pair {
+    F first;
+    S second;
+
+    Pair() { }
+    Pair(const Pair& o) : first(o.first), second(o.second) { }
+    Pair(const F& f, const S& s) : first(f), second(s)  { }
+
+    inline const F& getFirst() const {
+        return first;
+    }
+
+    inline const S& getSecond() const {
+        return second;
+    }
+};
+
+}; // namespace uirenderer
+
+template <typename F, typename S>
+struct trait_trivial_ctor< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_ctor }; };
+template <typename F, typename S>
+struct trait_trivial_dtor< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_dtor }; };
+template <typename F, typename S>
+struct trait_trivial_copy< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_copy }; };
+template <typename F, typename S>
+struct trait_trivial_move< uirenderer::Pair<F, S> >
+{ enum { value = aggregate_traits<F, S>::has_trivial_move }; };
+
+}; // namespace android
+
+#endif // ANDROID_HWUI_PAIR_H
diff --git a/location/java/android/location/IGeofenceProvider.aidl b/location/java/android/location/IGeofenceProvider.aidl
new file mode 100644
index 0000000..5a5fdc6
--- /dev/null
+++ b/location/java/android/location/IGeofenceProvider.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.location;
+
+import android.hardware.location.IGeofenceHardware;
+
+/**
+ * An interface for location providers implementing the Geofencing service
+ *
+ * {@hide}
+ */
+interface IGeofenceProvider {
+    void setGeofenceHardware(in IGeofenceHardware proxy);
+}
diff --git a/location/java/android/location/IGpsGeofenceHardware.aidl b/location/java/android/location/IGpsGeofenceHardware.aidl
new file mode 100644
index 0000000..764bf8e
--- /dev/null
+++ b/location/java/android/location/IGpsGeofenceHardware.aidl
@@ -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.
+ */
+
+package android.location;
+
+/**
+ * GPS hardware geofence
+ *
+ * @hide
+ */
+interface IGpsGeofenceHardware
+{
+    boolean isHardwareGeofenceSupported();
+    boolean addCircularHardwareGeofence(int geofenceId, double latitude, double
+            longitude, double radius, int lastTransition, int monitorTransition,
+            int notificationResponsiveness, int unknownTimer);
+    boolean removeHardwareGeofence(int geofenceId);
+    boolean pauseHardwareGeofence(int geofenceId);
+    boolean resumeHardwareGeofence(int geofenceId, int monitorTransition);
+}
diff --git a/location/lib/java/com/android/location/provider/GeofenceProvider.java b/location/lib/java/com/android/location/provider/GeofenceProvider.java
new file mode 100644
index 0000000..2618f34
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/GeofenceProvider.java
@@ -0,0 +1,67 @@
+/*
+ * 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.location.provider;
+
+import android.hardware.location.GeofenceHardware;
+import android.hardware.location.IGeofenceHardware;
+import android.os.IBinder;
+
+import android.location.IGeofenceProvider;
+import android.util.Log;
+
+import java.lang.Long;
+
+/**
+ * Base class for geofence providers implemented as unbundled services.
+ *
+ * <p>Geofence providers can be implemented as services and return the result of
+ * {@link com.android.location.provider.GeofenceProvider#getBinder()} in its getBinder() method.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled
+ * applications, and must remain API stable. See README.txt in the root
+ * of this package for more information.
+ */
+public abstract class GeofenceProvider {
+
+    private GeofenceHardware mGeofenceHardware;
+
+    private IGeofenceProvider.Stub mProvider = new IGeofenceProvider.Stub() {
+        public void setGeofenceHardware(IGeofenceHardware hardwareProxy) {
+            mGeofenceHardware = new GeofenceHardware(hardwareProxy);
+            onGeofenceHardwareChange(mGeofenceHardware);
+        }
+    };
+
+    /**
+     * Returns the Binder interface for the geofence provider.
+     * This is intended to be used for the onBind() method of
+     * a service that implements a geofence service.
+     *
+     * @return the IBinder instance for the provider
+     */
+    public IBinder getBinder() {
+        return mProvider;
+    }
+
+    /**
+     * Called when GeofenceHardware object becomes available.
+     *
+     * @param geofenceHardware Geofence Hardware object. This can be null
+     *        when for some reason the service connection gets disconnected.
+     */
+    public abstract void onGeofenceHardwareChange(GeofenceHardware geofenceHardware);
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 86976b8..917a47d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -50,6 +50,7 @@
     private long mVolumeKeyUpTime;
     private final boolean mUseMasterVolume;
     private final boolean mUseVolumeKeySounds;
+    private final Binder mToken = new Binder();
     private static String TAG = "AudioManager";
 
     /**
@@ -2047,18 +2048,36 @@
     }
 
     /**
+     * Register a component to be the sole receiver of MEDIA_BUTTON intents.  This is like
+     * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
+     * the buttons to go to any PendingIntent.  Note that you should only use this form if
+     * you know you will continue running for the full time until unregistering the
+     * PendingIntent.
+     * @param eventReceiver target that will receive media button intents.  The PendingIntent
+     * will be sent as-is when a media button action occurs, with {@link Intent#EXTRA_KEY_EVENT}
+     * added and holding the key code of the media button that was pressed.
+     */
+    public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
+        if (eventReceiver == null) {
+            return;
+        }
+        registerMediaButtonIntent(eventReceiver, null);
+    }
+
+    /**
      * @hide
      * no-op if (pi == null) or (eventReceiver == null)
      */
     public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
-        if ((pi == null) || (eventReceiver == null)) {
+        if (pi == null) {
             Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
             return;
         }
         IAudioService service = getService();
         try {
             // pi != null
-            service.registerMediaButtonIntent(pi, eventReceiver);
+            service.registerMediaButtonIntent(pi, eventReceiver,
+                    eventReceiver == null ? mToken : null);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
         }
@@ -2110,16 +2129,28 @@
         mediaButtonIntent.setComponent(eventReceiver);
         PendingIntent pi = PendingIntent.getBroadcast(mContext,
                 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
-        unregisterMediaButtonIntent(pi, eventReceiver);
+        unregisterMediaButtonIntent(pi);
+    }
+
+    /**
+     * Unregister the receiver of MEDIA_BUTTON intents.
+     * @param eventReceiver same PendingIntent that was registed with
+     *      {@link #registerMediaButtonEventReceiver(PendingIntent)}.
+     */
+    public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
+        if (eventReceiver == null) {
+            return;
+        }
+        unregisterMediaButtonIntent(eventReceiver);
     }
 
     /**
      * @hide
      */
-    public void unregisterMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
+    public void unregisterMediaButtonIntent(PendingIntent pi) {
         IAudioService service = getService();
         try {
-            service.unregisterMediaButtonIntent(pi, eventReceiver);
+            service.unregisterMediaButtonIntent(pi);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
         }
@@ -2171,15 +2202,36 @@
     /**
      * @hide
      * Registers a remote control display that will be sent information by remote control clients.
-     * @param rcd
+     * Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
+     * use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
+     * artwork size directly, or
+     * {@link #remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay, int, int)} later if artwork
+     * is not yet needed.
+     * @param rcd the IRemoteControlDisplay
      */
     public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        // passing a negative value for art work width and height as they are unknown at this stage
+        registerRemoteControlDisplay(rcd, /*w*/-1, /*h*/ -1);
+    }
+
+    /**
+     * @hide
+     * Registers a remote control display that will be sent information by remote control clients.
+     * @param rcd
+     * @param w the maximum width of the expected bitmap. Negative values indicate it is
+     *   useless to send artwork.
+     * @param h the maximum height of the expected bitmap. Negative values indicate it is
+     *   useless to send artwork.
+     */
+    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
         if (rcd == null) {
             return;
         }
         IAudioService service = getService();
         try {
-            service.registerRemoteControlDisplay(rcd);
+            // passing a negative value for art work width and height as they are unknown at
+            // this stage
+            service.registerRemoteControlDisplay(rcd, w, h);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
         }
@@ -2223,62 +2275,25 @@
         }
     }
 
-    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
     /**
      * @hide
-     * Broadcast intent action indicating that the displays on the remote controls
-     * should be updated because a new remote control client is now active. If there is no
-     * {@link #EXTRA_REMOTE_CONTROL_CLIENT}, the remote control display should be cleared
-     * because there is no valid client to supply it with information.
-     *
-     * @see #EXTRA_REMOTE_CONTROL_CLIENT
+     * Request the user of a RemoteControlClient to seek to the given playback position.
+     * @param generationId the RemoteControlClient generation counter for which this request is
+     *         issued. Requests for an older generation than current one will be ignored.
+     * @param timeMs the time in ms to seek to, must be positive.
      */
-    public static final String REMOTE_CONTROL_CLIENT_CHANGED =
-            "android.media.REMOTE_CONTROL_CLIENT_CHANGED";
-
-    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
-    /**
-     * @hide
-     * The IRemoteControlClientDispatcher monotonically increasing generation counter.
-     *
-     * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
-     */
-    public static final String EXTRA_REMOTE_CONTROL_CLIENT_GENERATION =
-            "android.media.EXTRA_REMOTE_CONTROL_CLIENT_GENERATION";
-
-    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
-    /**
-     * @hide
-     * The name of the RemoteControlClient.
-     * This String is passed as the client name when calling methods from the
-     * IRemoteControlClientDispatcher interface.
-     *
-     * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
-     */
-    public static final String EXTRA_REMOTE_CONTROL_CLIENT_NAME =
-            "android.media.EXTRA_REMOTE_CONTROL_CLIENT_NAME";
-
-    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
-    /**
-     * @hide
-     * The media button event receiver associated with the RemoteControlClient.
-     * The {@link android.content.ComponentName} value of the event receiver can be retrieved with
-     * {@link android.content.ComponentName#unflattenFromString(String)}
-     *
-     * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
-     */
-    public static final String EXTRA_REMOTE_CONTROL_EVENT_RECEIVER =
-            "android.media.EXTRA_REMOTE_CONTROL_EVENT_RECEIVER";
-
-    // FIXME remove because we are not using intents anymore between AudioService and RcDisplay
-    /**
-     * @hide
-     * The flags describing what information has changed in the current remote control client.
-     *
-     * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
-     */
-    public static final String EXTRA_REMOTE_CONTROL_CLIENT_INFO_CHANGED =
-            "android.media.EXTRA_REMOTE_CONTROL_CLIENT_INFO_CHANGED";
+    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        if (timeMs < 0) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            service.setRemoteControlClientPlaybackPosition(generationId, timeMs);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setRccPlaybackPosition("+ generationId + ", "
+                    + timeMs + ")", e);
+        }
+    }
 
     /**
      *  @hide
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ed2a8da..637ac85 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -42,6 +42,8 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
@@ -70,10 +72,14 @@
 import android.view.VolumePanel;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.HashMap;
@@ -158,11 +164,10 @@
     private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27;
     private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28;
     private static final int MSG_PROMOTE_RCC = 29;
-
-    // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
-    // persisted
-    private static final int PERSIST_CURRENT = 0x1;
-    private static final int PERSIST_LAST_AUDIBLE = 0x2;
+    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 30;
+    private static final int MSG_UNLOAD_SOUND_EFFECTS = 31;
+    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 32;
+    private static final int MSG_RCC_SEEK_REQUEST = 33;
 
     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
     // Timeout for connection to bluetooth headset service
@@ -195,28 +200,12 @@
 
     /* Sound effect file names  */
     private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
-    private static final String[] SOUND_EFFECT_FILES = new String[] {
-        "Effect_Tick.ogg",
-        "KeypressStandard.ogg",
-        "KeypressSpacebar.ogg",
-        "KeypressDelete.ogg",
-        "KeypressReturn.ogg"
-    };
+    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
 
     /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
      * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
      * uses soundpool (second column) */
-    private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
-        {0, -1},  // FX_KEY_CLICK
-        {0, -1},  // FX_FOCUS_NAVIGATION_UP
-        {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
-        {0, -1},  // FX_FOCUS_NAVIGATION_LEFT
-        {0, -1},  // FX_FOCUS_NAVIGATION_RIGHT
-        {1, -1},  // FX_KEYPRESS_STANDARD
-        {2, -1},  // FX_KEYPRESS_SPACEBAR
-        {3, -1},  // FX_FOCUS_DELETE
-        {4, -1}   // FX_FOCUS_RETURN
-    };
+    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
 
    /** @hide Maximum volume index values for audio streams */
     private final int[] MAX_STREAM_VOLUME = new int[] {
@@ -265,6 +254,8 @@
     };
     private int[] mStreamVolumeAlias;
 
+    private final boolean mUseFixedVolume;
+
     // stream names used by dumpStreamStates()
     private final String[] STREAM_NAMES = new String[] {
             "STREAM_VOICE_CALL",
@@ -366,7 +357,7 @@
     private static final int SCO_STATE_INACTIVE = 0;
     // SCO audio activation request waiting for headset service to connect
     private static final int SCO_STATE_ACTIVATE_REQ = 1;
-    // SCO audio state is active or starting due to a local request to start a virtual call
+    // SCO audio state is active or starting due to a request from AudioManager API
     private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
     // SCO audio deactivation request waiting for headset service to connect
     private static final int SCO_STATE_DEACTIVATE_REQ = 5;
@@ -495,6 +486,9 @@
         mSafeMediaVolumeIndex = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
 
+        mUseFixedVolume = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useFixedVolume);
+
         readPersistedSettings();
         mSettingsObserver = new SettingsObserver();
         updateStreamVolumeAlias(false /*updateVolumes*/);
@@ -536,6 +530,9 @@
         // Register for package removal intent broadcasts for media button receiver persistence
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
         pkgFilter.addDataScheme("package");
         context.registerReceiver(mReceiver, pkgFilter);
 
@@ -583,14 +580,10 @@
         for (int streamType = 0; streamType < numStreamTypes; streamType++) {
             if (streamType != mStreamVolumeAlias[streamType]) {
                 mStreamStates[streamType].
-                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
-                                                  false /*lastAudible*/);
-                mStreamStates[streamType].
-                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
-                                                  true /*lastAudible*/);
+                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
             }
             // apply stream volume
-            if (mStreamStates[streamType].muteCount() == 0) {
+            if (!mStreamStates[streamType].isMuted()) {
                 mStreamStates[streamType].applyAllVolumes();
             }
         }
@@ -634,10 +627,7 @@
         }
         mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
         if (updateVolumes) {
-            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
-                                                                 false /*lastAudible*/);
-            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
-                                                                 true /*lastAudible*/);
+            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
             sendMsg(mAudioHandler,
                     MSG_SET_ALL_VOLUMES,
                     SENDMSG_QUEUE,
@@ -686,6 +676,9 @@
         if (ringerMode != ringerModeFromSettings) {
             Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
         }
+        if (mUseFixedVolume) {
+            ringerMode = AudioManager.RINGER_MODE_NORMAL;
+        }
         synchronized(mSettingsLock) {
             mRingerMode = ringerMode;
 
@@ -744,6 +737,10 @@
 
         boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
                                                   0, UserHandle.USER_CURRENT) == 1;
+        if (mUseFixedVolume) {
+            masterMute = false;
+            AudioSystem.setMasterVolume(1.0f);
+        }
         AudioSystem.setMasterMute(masterMute);
         broadcastMasterMuteStatus(masterMute);
 
@@ -784,7 +781,7 @@
         }
     }
 
-    /** @see AudioManager#adjustVolume(int, int, int) */
+    /** @see AudioManager#adjustVolume(int, int) */
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
         if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
         int streamType;
@@ -814,6 +811,9 @@
 
     /** @see AudioManager#adjustStreamVolume(int, int, int) */
     public void adjustStreamVolume(int streamType, int direction, int flags) {
+        if (mUseFixedVolume) {
+            return;
+        }
         if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
 
         ensureValidDirection(direction);
@@ -827,14 +827,9 @@
 
         final int device = getDeviceForStream(streamTypeAlias);
 
-        // get last audible index if stream is muted, current index otherwise
-        int aliasIndex = streamState.getIndex(device,
-                        (streamState.muteCount() != 0) /* lastAudible */);
+        int aliasIndex = streamState.getIndex(device);
         boolean adjustVolume = true;
-
         int step;
-        int index;
-        int oldIndex;
 
         // reset any pending volume command
         synchronized (mSafeMediaVolumeState) {
@@ -863,69 +858,48 @@
             step = rescaleIndex(10, streamType, streamTypeAlias);
         }
 
-        if ((direction == AudioManager.ADJUST_RAISE) &&
-                !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
-            index = mStreamStates[streamType].getIndex(device,
-                                                 (streamState.muteCount() != 0)  /* lastAudible */);
-            oldIndex = index;
-            mVolumePanel.postDisplaySafeVolumeWarning(flags);
-        } else {
-            // If either the client forces allowing ringer modes for this adjustment,
-            // or the stream type is one that is affected by ringer modes
-            if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
-                    (streamTypeAlias == getMasterStreamType())) {
-                int ringerMode = getRingerMode();
-                // do not vibrate if already in vibrate mode
-                if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-                    flags &= ~AudioManager.FLAG_VIBRATE;
-                }
-                // Check if the ringer mode changes with this volume adjustment. If
-                // it does, it will handle adjusting the volume, so we won't below
-                adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
-                if ((streamTypeAlias == getMasterStreamType()) &&
-                        (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
-                    streamState.setLastAudibleIndex(0, device);
-                }
+        // If either the client forces allowing ringer modes for this adjustment,
+        // or the stream type is one that is affected by ringer modes
+        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
+                (streamTypeAlias == getMasterStreamType())) {
+            int ringerMode = getRingerMode();
+            // do not vibrate if already in vibrate mode
+            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+                flags &= ~AudioManager.FLAG_VIBRATE;
             }
+            // Check if the ringer mode changes with this volume adjustment. If
+            // it does, it will handle adjusting the volume, so we won't below
+            adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
+        }
 
-            // If stream is muted, adjust last audible index only
-            oldIndex = mStreamStates[streamType].getIndex(device,
-                    (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
+        int oldIndex = mStreamStates[streamType].getIndex(device);
 
-            if (streamState.muteCount() != 0) {
-                if (adjustVolume) {
-                    // Post a persist volume msg
-                    // no need to persist volume on all streams sharing the same alias
-                    streamState.adjustLastAudibleIndex(direction * step, device);
-                    sendMsg(mAudioHandler,
-                            MSG_PERSIST_VOLUME,
-                            SENDMSG_QUEUE,
-                            PERSIST_LAST_AUDIBLE,
-                            device,
-                            streamState,
-                            PERSIST_DELAY);
-                }
-                index = mStreamStates[streamType].getIndex(device, true  /* lastAudible */);
-            } else {
-                if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
-                    // Post message to set system volume (it in turn will post a message
-                    // to persist). Do not change volume if stream is muted.
-                    sendMsg(mAudioHandler,
-                            MSG_SET_DEVICE_VOLUME,
-                            SENDMSG_QUEUE,
-                            device,
-                            0,
-                            streamState,
-                            0);
-                }
-                index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
+        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+            if ((direction == AudioManager.ADJUST_RAISE) &&
+                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
+                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
+                mVolumePanel.postDisplaySafeVolumeWarning(flags);
+            } else if (streamState.adjustIndex(direction * step, device)) {
+                // Post message to set system volume (it in turn will post a message
+                // to persist). Do not change volume if stream is muted.
+                sendMsg(mAudioHandler,
+                        MSG_SET_DEVICE_VOLUME,
+                        SENDMSG_QUEUE,
+                        device,
+                        0,
+                        streamState,
+                        0);
             }
         }
+        int index = mStreamStates[streamType].getIndex(device);
         sendVolumeUpdate(streamType, oldIndex, index, flags);
     }
 
-    /** @see AudioManager#adjustMasterVolume(int) */
+    /** @see AudioManager#adjustMasterVolume(int, int) */
     public void adjustMasterVolume(int steps, int flags) {
+        if (mUseFixedVolume) {
+            return;
+        }
         ensureValidSteps(steps);
         int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
         int delta = 0;
@@ -957,6 +931,7 @@
     };
 
     private void onSetStreamVolume(int streamType, int index, int flags, int device) {
+        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
         // setting volume on master stream type also controls silent mode
         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
                 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
@@ -964,22 +939,19 @@
             if (index == 0) {
                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
                                               : AudioManager.RINGER_MODE_SILENT;
-                setStreamVolumeInt(mStreamVolumeAlias[streamType],
-                                   index,
-                                   device,
-                                   false,
-                                   true);
             } else {
                 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
             }
             setRingerMode(newRingerMode);
         }
-
-        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true);
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
     public void setStreamVolume(int streamType, int index, int flags) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
         ensureValidStreamType(streamType);
         VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
 
@@ -990,9 +962,7 @@
             // reset any pending volume command
             mPendingVolumeCommand = null;
 
-            // get last audible index if stream is muted, current index otherwise
-            oldIndex = streamState.getIndex(device,
-                                            (streamState.muteCount() != 0) /* lastAudible */);
+            oldIndex = streamState.getIndex(device);
 
             index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
 
@@ -1018,9 +988,7 @@
                                                     streamType, index, flags, device);
             } else {
                 onSetStreamVolume(streamType, index, flags, device);
-                // get last audible index if stream is muted, current index otherwise
-                index = mStreamStates[streamType].getIndex(device,
-                                    (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
+                index = mStreamStates[streamType].getIndex(device);
             }
         }
         sendVolumeUpdate(streamType, oldIndex, index, flags);
@@ -1182,55 +1150,44 @@
      * @param device the device whose volume must be changed
      * @param force If true, set the volume even if the desired volume is same
      * as the current volume.
-     * @param lastAudible If true, stores new index as last audible one
      */
     private void setStreamVolumeInt(int streamType,
                                     int index,
                                     int device,
-                                    boolean force,
-                                    boolean lastAudible) {
+                                    boolean force) {
         VolumeStreamState streamState = mStreamStates[streamType];
 
-        // If stream is muted, set last audible index only
-        if (streamState.muteCount() != 0) {
-            // Do not allow last audible index to be 0
-            if (index != 0) {
-                streamState.setLastAudibleIndex(index, device);
-                // Post a persist volume msg
-                sendMsg(mAudioHandler,
-                        MSG_PERSIST_VOLUME,
-                        SENDMSG_QUEUE,
-                        PERSIST_LAST_AUDIBLE,
-                        device,
-                        streamState,
-                        PERSIST_DELAY);
-            }
-        } else {
-            if (streamState.setIndex(index, device, lastAudible) || force) {
-                // Post message to set system volume (it in turn will post a message
-                // to persist).
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        device,
-                        0,
-                        streamState,
-                        0);
-            }
+        if (streamState.setIndex(index, device) || force) {
+            // Post message to set system volume (it in turn will post a message
+            // to persist).
+            sendMsg(mAudioHandler,
+                    MSG_SET_DEVICE_VOLUME,
+                    SENDMSG_QUEUE,
+                    device,
+                    0,
+                    streamState,
+                    0);
         }
     }
 
     /** @see AudioManager#setStreamSolo(int, boolean) */
     public void setStreamSolo(int streamType, boolean state, IBinder cb) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
         for (int stream = 0; stream < mStreamStates.length; stream++) {
             if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
-            // Bring back last audible volume
             mStreamStates[stream].mute(cb, state);
          }
     }
 
     /** @see AudioManager#setStreamMute(int, boolean) */
     public void setStreamMute(int streamType, boolean state, IBinder cb) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
         if (isStreamAffectedByMute(streamType)) {
             mStreamStates[streamType].mute(cb, state);
         }
@@ -1238,11 +1195,15 @@
 
     /** get stream mute state. */
     public boolean isStreamMute(int streamType) {
-        return (mStreamStates[streamType].muteCount() != 0);
+        return mStreamStates[streamType].isMuted();
     }
 
-    /** @see AudioManager#setMasterMute(boolean, IBinder) */
+    /** @see AudioManager#setMasterMute(boolean, int) */
     public void setMasterMute(boolean state, int flags, IBinder cb) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
         if (state != AudioSystem.getMasterMute()) {
             AudioSystem.setMasterMute(state);
             // Post a persist master volume msg
@@ -1261,8 +1222,12 @@
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
         int device = getDeviceForStream(streamType);
-        int index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
+        int index = mStreamStates[streamType].getIndex(device);
 
+        // by convention getStreamVolume() returns 0 when a stream is muted.
+        if (mStreamStates[streamType].isMuted()) {
+            index = 0;
+        }
         if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
                 (device & mFixedVolumeDevices) != 0) {
             index = mStreamStates[streamType].getMaxIndex();
@@ -1276,6 +1241,10 @@
     }
 
     public void setMasterVolume(int volume, int flags) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
         if (volume < 0) {
             volume = 0;
         } else if (volume > MAX_MASTER_VOLUME) {
@@ -1315,7 +1284,7 @@
     public int getLastAudibleStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
         int device = getDeviceForStream(streamType);
-        return (mStreamStates[streamType].getIndex(device, true  /* lastAudible */) + 5) / 10;
+        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
     }
 
     /** Get last audible master volume before it was muted. */
@@ -1323,7 +1292,7 @@
         return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
     }
 
-    /** @see AudioManager#getMasterStreamType(int) */
+    /** @see AudioManager#getMasterStreamType()  */
     public int getMasterStreamType() {
         if (mVoiceCapable) {
             return AudioSystem.STREAM_RING;
@@ -1347,6 +1316,10 @@
 
     /** @see AudioManager#setRingerMode(int) */
     public void setRingerMode(int ringerMode) {
+        if (mUseFixedVolume) {
+            return;
+        }
+
         if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
             ringerMode = AudioManager.RINGER_MODE_SILENT;
         }
@@ -1376,7 +1349,7 @@
                     if (mVoiceCapable &&
                             mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
                         synchronized (mStreamStates[streamType]) {
-                            Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
+                            Set set = mStreamStates[streamType].mIndex.entrySet();
                             Iterator i = set.iterator();
                             while (i.hasNext()) {
                                 Map.Entry entry = (Map.Entry)i.next();
@@ -1406,6 +1379,10 @@
     }
 
     private void restoreMasterVolume() {
+        if (mUseFixedVolume) {
+            AudioSystem.setMasterVolume(1.0f);
+            return;
+        }
         if (mUseMasterVolume) {
             float volume = Settings.System.getFloatForUser(mContentResolver,
                     Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
@@ -1494,7 +1471,9 @@
             // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
             // SCO connections not started by the application changing the mode
             if (newModeOwnerPid != 0) {
-                 disconnectBluetoothSco(newModeOwnerPid);
+                final long ident = Binder.clearCallingIdentity();
+                disconnectBluetoothSco(newModeOwnerPid);
+                Binder.restoreCallingIdentity(ident);
             }
         }
 
@@ -1619,8 +1598,8 @@
                 streamType = AudioManager.STREAM_MUSIC;
             }
             int device = getDeviceForStream(streamType);
-            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false);
-            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false);
+            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
+            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
 
             updateStreamVolumeAlias(true /*updateVolumes*/);
         }
@@ -1632,16 +1611,118 @@
         return mMode;
     }
 
+    //==========================================================================================
+    // Sound Effects
+    //==========================================================================================
+
+    private static final String TAG_AUDIO_ASSETS = "audio_assets";
+    private static final String ATTR_VERSION = "version";
+    private static final String TAG_GROUP = "group";
+    private static final String ATTR_GROUP_NAME = "name";
+    private static final String TAG_ASSET = "asset";
+    private static final String ATTR_ASSET_ID = "id";
+    private static final String ATTR_ASSET_FILE = "file";
+
+    private static final String ASSET_FILE_VERSION = "1.0";
+    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
+
+    private static final int SOUND_EFECTS_LOAD_TIMEOUT_MS = 5000;
+
+    class LoadSoundEffectReply {
+        public int mStatus = 1;
+    };
+
+    private void loadTouchSoundAssetDefaults() {
+        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
+        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
+            SOUND_EFFECT_FILES_MAP[i][0] = 0;
+            SOUND_EFFECT_FILES_MAP[i][1] = -1;
+        }
+    }
+
+    private void loadTouchSoundAssets() {
+        XmlResourceParser parser = null;
+
+        // only load assets once.
+        if (!SOUND_EFFECT_FILES.isEmpty()) {
+            return;
+        }
+
+        loadTouchSoundAssetDefaults();
+
+        try {
+            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
+
+            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
+            String version = parser.getAttributeValue(null, ATTR_VERSION);
+            boolean inTouchSoundsGroup = false;
+
+            if (ASSET_FILE_VERSION.equals(version)) {
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals(TAG_GROUP)) {
+                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
+                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
+                            inTouchSoundsGroup = true;
+                            break;
+                        }
+                    }
+                }
+                while (inTouchSoundsGroup) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals(TAG_ASSET)) {
+                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
+                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
+                        int fx;
+
+                        try {
+                            Field field = AudioManager.class.getField(id);
+                            fx = field.getInt(null);
+                        } catch (Exception e) {
+                            Log.w(TAG, "Invalid touch sound ID: "+id);
+                            continue;
+                        }
+
+                        int i = SOUND_EFFECT_FILES.indexOf(file);
+                        if (i == -1) {
+                            i = SOUND_EFFECT_FILES.size();
+                            SOUND_EFFECT_FILES.add(file);
+                        }
+                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
+                    } else {
+                        break;
+                    }
+                }
+            }
+        } catch (Resources.NotFoundException e) {
+            Log.w(TAG, "audio assets file not found", e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "XML parser exception reading touch sound assets", e);
+        } catch (IOException e) {
+            Log.w(TAG, "I/O exception reading touch sound assets", e);
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+
     /** @see AudioManager#playSoundEffect(int) */
     public void playSoundEffect(int effectType) {
-        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
-                effectType, -1, null, 0);
+        playSoundEffectVolume(effectType, -1.0f);
     }
 
     /** @see AudioManager#playSoundEffect(int, float) */
     public void playSoundEffectVolume(int effectType, float volume) {
-        loadSoundEffects();
-        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
+        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
                 effectType, (int) (volume * 1000), null, 0);
     }
 
@@ -1650,114 +1731,20 @@
      * This method must be called at first when sound effects are enabled
      */
     public boolean loadSoundEffects() {
-        int status;
+        int attempts = 3;
+        LoadSoundEffectReply reply = new LoadSoundEffectReply();
 
-        synchronized (mSoundEffectsLock) {
-            if (!mBootCompleted) {
-                Log.w(TAG, "loadSoundEffects() called before boot complete");
-                return false;
-            }
-
-            if (mSoundPool != null) {
-                return true;
-            }
-            mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
-
-            try {
-                mSoundPoolCallBack = null;
-                mSoundPoolListenerThread = new SoundPoolListenerThread();
-                mSoundPoolListenerThread.start();
-                // Wait for mSoundPoolCallBack to be set by the other thread
-                mSoundEffectsLock.wait();
-            } catch (InterruptedException e) {
-                Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
-            }
-
-            if (mSoundPoolCallBack == null) {
-                Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread");
-                if (mSoundPoolLooper != null) {
-                    mSoundPoolLooper.quit();
-                    mSoundPoolLooper = null;
-                }
-                mSoundPoolListenerThread = null;
-                mSoundPool.release();
-                mSoundPool = null;
-                return false;
-            }
-            /*
-             * poolId table: The value -1 in this table indicates that corresponding
-             * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
-             * Once loaded, the value in poolId is the sample ID and the same
-             * sample can be reused for another effect using the same file.
-             */
-            int[] poolId = new int[SOUND_EFFECT_FILES.length];
-            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
-                poolId[fileIdx] = -1;
-            }
-            /*
-             * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
-             * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
-             * this indicates we have a valid sample loaded for this effect.
-             */
-
-            int lastSample = 0;
-            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                // Do not load sample if this effect uses the MediaPlayer
-                if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
-                    continue;
-                }
-                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
-                    String filePath = Environment.getRootDirectory()
-                            + SOUND_EFFECTS_PATH
-                            + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
-                    int sampleId = mSoundPool.load(filePath, 0);
-                    if (sampleId <= 0) {
-                        Log.w(TAG, "Soundpool could not load file: "+filePath);
-                    } else {
-                        SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
-                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
-                        lastSample = sampleId;
-                    }
-                } else {
-                    SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
-                }
-            }
-            // wait for all samples to be loaded
-            if (lastSample != 0) {
-                mSoundPoolCallBack.setLastSample(lastSample);
-
+        synchronized (reply) {
+            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
+            while ((reply.mStatus == 1) && (attempts-- > 0)) {
                 try {
-                    mSoundEffectsLock.wait();
-                    status = mSoundPoolCallBack.status();
-                } catch (java.lang.InterruptedException e) {
-                    Log.w(TAG, "Interrupted while waiting sound pool callback.");
-                    status = -1;
+                    reply.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
                 }
-            } else {
-                status = -1;
-            }
-
-            if (mSoundPoolLooper != null) {
-                mSoundPoolLooper.quit();
-                mSoundPoolLooper = null;
-            }
-            mSoundPoolListenerThread = null;
-            if (status != 0) {
-                Log.w(TAG,
-                        "loadSoundEffects(), Error "
-                                + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1)
-                                + " while loading samples");
-                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                    if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
-                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
-                    }
-                }
-
-                mSoundPool.release();
-                mSoundPool = null;
             }
         }
-        return (status == 0);
+        return (reply.mStatus == 0);
     }
 
     /**
@@ -1766,32 +1753,7 @@
      *  sound effects are disabled.
      */
     public void unloadSoundEffects() {
-        synchronized (mSoundEffectsLock) {
-            if (mSoundPool == null) {
-                return;
-            }
-
-            mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS);
-            mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT);
-
-            int[] poolId = new int[SOUND_EFFECT_FILES.length];
-            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
-                poolId[fileIdx] = 0;
-            }
-
-            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
-                if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
-                    continue;
-                }
-                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
-                    mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
-                    SOUND_EFFECT_FILES_MAP[effect][1] = -1;
-                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
-                }
-            }
-            mSoundPool.release();
-            mSoundPool = null;
-        }
+        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
     }
 
     class SoundPoolListenerThread extends Thread {
@@ -1819,23 +1781,30 @@
     private final class SoundPoolCallback implements
             android.media.SoundPool.OnLoadCompleteListener {
 
-        int mStatus;
-        int mLastSample;
+        int mStatus = 1; // 1 means neither error nor last sample loaded yet
+        List<Integer> mSamples = new ArrayList<Integer>();
 
         public int status() {
             return mStatus;
         }
 
-        public void setLastSample(int sample) {
-            mLastSample = sample;
+        public void setSamples(int[] samples) {
+            for (int i = 0; i < samples.length; i++) {
+                // do not wait ack for samples rejected upfront by SoundPool
+                if (samples[i] > 0) {
+                    mSamples.add(samples[i]);
+                }
+            }
         }
 
         public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
             synchronized (mSoundEffectsLock) {
-                if (status != 0) {
-                    mStatus = status;
+                int i = mSamples.indexOf(sampleId);
+                if (i >= 0) {
+                    mSamples.remove(i);
                 }
-                if (sampleId == mLastSample) {
+                if ((status != 0) || mSamples. isEmpty()) {
+                    mStatus = status;
                     mSoundEffectsLock.notify();
                 }
             }
@@ -1864,8 +1833,8 @@
                 streamState.readSettings();
 
                 // unmute stream that was muted but is not affect by mute anymore
-                if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType) &&
-                        !isStreamMutedByRingerMode(streamType)) {
+                if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
+                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
                     int size = streamState.mDeathHandlers.size();
                     for (int i = 0; i < size; i++) {
                         streamState.mDeathHandlers.get(i).mMuteCount = 1;
@@ -1888,7 +1857,7 @@
         }
     }
 
-    /** @see AudioManager#setSpeakerphoneOn() */
+    /** @see AudioManager#setSpeakerphoneOn(boolean) */
     public void setSpeakerphoneOn(boolean on){
         if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
             return;
@@ -1904,7 +1873,7 @@
         return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
     }
 
-    /** @see AudioManager#setBluetoothScoOn() */
+    /** @see AudioManager#setBluetoothScoOn(boolean) */
     public void setBluetoothScoOn(boolean on){
         if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
             return;
@@ -1922,7 +1891,7 @@
         return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
     }
 
-    /** @see AudioManager#setBluetoothA2dpOn() */
+    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
     public void setBluetoothA2dpOn(boolean on) {
         synchronized (mBluetoothA2dpEnabledLock) {
             mBluetoothA2dpEnabled = on;
@@ -1947,7 +1916,14 @@
             return;
         }
         ScoClient client = getScoClient(cb, true);
+        // The calling identity must be cleared before calling ScoClient.incCount().
+        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
+        // and this must be done on behalf of system server to make sure permissions are granted.
+        // 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();
+        Binder.restoreCallingIdentity(ident);
     }
 
     /** @see AudioManager#stopBluetoothSco() */
@@ -1957,9 +1933,14 @@
             return;
         }
         ScoClient client = getScoClient(cb, false);
+        // The calling identity must be cleared before calling ScoClient.decCount().
+        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
+        // and this must be done on behalf of system server to make sure permissions are granted.
+        final long ident = Binder.clearCallingIdentity();
         if (client != null) {
             client.decCount();
         }
+        Binder.restoreCallingIdentity(ident);
     }
 
 
@@ -2075,8 +2056,7 @@
                                  mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
                             if (mScoAudioState == SCO_STATE_INACTIVE) {
                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                    if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                            mBluetoothHeadsetDevice)) {
+                                    if (mBluetoothHeadset.connectAudio()) {
                                         mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
                                     } else {
                                         broadcastScoConnectionState(
@@ -2098,8 +2078,7 @@
                                mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
                     if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
                         if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                            if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
-                                    mBluetoothHeadsetDevice)) {
+                            if (!mBluetoothHeadset.disconnectAudio()) {
                                 mScoAudioState = SCO_STATE_INACTIVE;
                                 broadcastScoConnectionState(
                                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -2209,6 +2188,11 @@
     }
 
     private void broadcastScoConnectionState(int state) {
+        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
+                SENDMSG_QUEUE, state, 0, null, 0);
+    }
+
+    private void onBroadcastScoConnectionState(int state) {
         if (state != mScoConnectionState) {
             Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
             newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
@@ -2267,12 +2251,10 @@
                             switch (mScoAudioState) {
                             case SCO_STATE_ACTIVATE_REQ:
                                 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
-                                        mBluetoothHeadsetDevice);
+                                status = mBluetoothHeadset.connectAudio();
                                 break;
                             case SCO_STATE_DEACTIVATE_REQ:
-                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
-                                        mBluetoothHeadsetDevice);
+                                status = mBluetoothHeadset.disconnectAudio();
                                 break;
                             case SCO_STATE_DEACTIVATE_EXT_REQ:
                                 status = mBluetoothHeadset.stopVoiceRecognition(
@@ -2347,8 +2329,7 @@
                             0,
                             null,
                             MUSIC_ACTIVE_POLL_PERIOD_MS);
-                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device,
-                                                                            false /*lastAudible*/);
+                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
                     if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
                             (index > mSafeMediaVolumeIndex)) {
                         // Approximate cumulative active music time
@@ -2693,18 +2674,14 @@
         private final int mStreamType;
 
         private String mVolumeIndexSettingName;
-        private String mLastAudibleVolumeIndexSettingName;
         private int mIndexMax;
         private final ConcurrentHashMap<Integer, Integer> mIndex =
                                             new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
-        private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
-                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
         private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
 
         private VolumeStreamState(String settingName, int streamType) {
 
             mVolumeIndexSettingName = settingName;
-            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
 
             mStreamType = streamType;
             mIndexMax = MAX_STREAM_VOLUME[streamType];
@@ -2717,10 +2694,8 @@
             readSettings();
         }
 
-        public String getSettingNameForDevice(boolean lastAudible, int device) {
-            String name = lastAudible ?
-                            mLastAudibleVolumeIndexSettingName :
-                            mVolumeIndexSettingName;
+        public String getSettingNameForDevice(int device) {
+            String name = mVolumeIndexSettingName;
             String suffix = AudioSystem.getDeviceName(device);
             if (suffix.isEmpty()) {
                 return name;
@@ -2729,13 +2704,14 @@
         }
 
         public synchronized void readSettings() {
-            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
-
+            // force maximum volume on all streams if fixed volume property is set
+            if (mUseFixedVolume) {
+                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
+                return;
+            }
             // do not read system stream volume from settings: this stream is always aliased
             // to another stream type and its volume is never persisted. Values in settings can
             // only be stale values
-            // on first call to readSettings() at init time, muteCount() is always 0 so we will
-            // always create entries for default device
             if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
                     (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
                 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
@@ -2744,13 +2720,12 @@
                         index = mIndexMax;
                     }
                 }
-                if (muteCount() == 0) {
-                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
-                }
-                mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
+                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
                 return;
             }
 
+            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
+
             for (int i = 0; remainingDevices != 0; i++) {
                 int device = (1 << i);
                 if ((device & remainingDevices) == 0) {
@@ -2759,7 +2734,7 @@
                 remainingDevices &= ~device;
 
                 // retrieve current volume for device
-                String name = getSettingNameForDevice(false /* lastAudible */, device);
+                String name = getSettingNameForDevice(device);
                 // if no volume stored for current stream and device, use default volume if default
                 // device, continue otherwise
                 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
@@ -2773,72 +2748,33 @@
                 // ignore settings for fixed volume devices: volume should always be at max or 0
                 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
                         ((device & mFixedVolumeDevices) != 0)) {
-                    if ((muteCount()) == 0 && (index != 0)) {
-                        mIndex.put(device, mIndexMax);
-                    } else {
-                        mIndex.put(device, 0);
-                    }
-                    mLastAudibleIndex.put(device, mIndexMax);
-                    continue;
-                }
-
-                // retrieve last audible volume for device
-                name = getSettingNameForDevice(true  /* lastAudible */, device);
-                // use stored last audible index if present, otherwise use current index if not 0
-                // or default index
-                defaultIndex = (index > 0) ?
-                                    index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
-                int lastAudibleIndex = Settings.System.getIntForUser(
-                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
-
-                // a last audible index of 0 should never be stored for ring and notification
-                // streams on phones (voice capable devices).
-                if ((lastAudibleIndex == 0) && mVoiceCapable &&
-                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) {
-                    lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
-                    // Correct the data base
-                    sendMsg(mAudioHandler,
-                            MSG_PERSIST_VOLUME,
-                            SENDMSG_QUEUE,
-                            PERSIST_LAST_AUDIBLE,
-                            device,
-                            this,
-                            PERSIST_DELAY);
-                }
-                mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex));
-                // the initial index should never be 0 for ring and notification streams on phones
-                // (voice capable devices) if not in silent or vibrate mode.
-                if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) &&
-                        mVoiceCapable &&
-                        (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) {
-                    index = lastAudibleIndex;
-                    // Correct the data base
-                    sendMsg(mAudioHandler,
-                            MSG_PERSIST_VOLUME,
-                            SENDMSG_QUEUE,
-                            PERSIST_CURRENT,
-                            device,
-                            this,
-                            PERSIST_DELAY);
-                }
-                if (muteCount() == 0) {
+                    mIndex.put(device, (index != 0) ? mIndexMax : 0);
+                } else {
                     mIndex.put(device, getValidIndex(10 * index));
                 }
             }
         }
 
         public void applyDeviceVolume(int device) {
-            AudioSystem.setStreamVolumeIndex(mStreamType,
-                                             (getIndex(device, false  /* lastAudible */) + 5)/10,
-                                             device);
+            int index;
+            if (isMuted()) {
+                index = 0;
+            } else {
+                index = (getIndex(device) + 5)/10;
+            }
+            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
         }
 
         public synchronized void applyAllVolumes() {
             // apply default volume first: by convention this will reset all
             // devices volumes in audio policy manager to the supplied value
-            AudioSystem.setStreamVolumeIndex(mStreamType,
-                    (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10,
-                    AudioSystem.DEVICE_OUT_DEFAULT);
+            int index;
+            if (isMuted()) {
+                index = 0;
+            } else {
+                index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
+            }
+            AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
             // then apply device specific volumes
             Set set = mIndex.entrySet();
             Iterator i = set.iterator();
@@ -2846,34 +2782,32 @@
                 Map.Entry entry = (Map.Entry)i.next();
                 int device = ((Integer)entry.getKey()).intValue();
                 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
-                    AudioSystem.setStreamVolumeIndex(mStreamType,
-                                                     ((Integer)entry.getValue() + 5)/10,
-                                                     device);
+                    if (isMuted()) {
+                        index = 0;
+                    } else {
+                        index = ((Integer)entry.getValue() + 5)/10;
+                    }
+                    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
                 }
             }
         }
 
         public boolean adjustIndex(int deltaIndex, int device) {
-            return setIndex(getIndex(device,
-                                     false  /* lastAudible */) + deltaIndex,
-                            device,
-                            true  /* lastAudible */);
+            return setIndex(getIndex(device) + deltaIndex,
+                            device);
         }
 
-        public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
-            int oldIndex = getIndex(device, false  /* lastAudible */);
+        public synchronized boolean setIndex(int index, int device) {
+            int oldIndex = getIndex(device);
             index = getValidIndex(index);
             synchronized (mCameraSoundForced) {
                 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
                     index = mIndexMax;
                 }
             }
-            mIndex.put(device, getValidIndex(index));
+            mIndex.put(device, index);
 
             if (oldIndex != index) {
-                if (lastAudible) {
-                    mLastAudibleIndex.put(device, index);
-                }
                 // Apply change to all streams using this one as alias
                 // if changing volume of current device, also change volume of current
                 // device on aliased stream
@@ -2884,12 +2818,10 @@
                             mStreamVolumeAlias[streamType] == mStreamType) {
                         int scaledIndex = rescaleIndex(index, mStreamType, streamType);
                         mStreamStates[streamType].setIndex(scaledIndex,
-                                                           device,
-                                                           lastAudible);
+                                                           device);
                         if (currentDevice) {
                             mStreamStates[streamType].setIndex(scaledIndex,
-                                                               getDeviceForStream(streamType),
-                                                               lastAudible);
+                                                               getDeviceForStream(streamType));
                         }
                     }
                 }
@@ -2899,63 +2831,21 @@
             }
         }
 
-        public synchronized int getIndex(int device, boolean lastAudible) {
-            ConcurrentHashMap <Integer, Integer> indexes;
-            if (lastAudible) {
-                indexes = mLastAudibleIndex;
-            } else {
-                indexes = mIndex;
-            }
-            Integer index = indexes.get(device);
+        public synchronized int getIndex(int device) {
+            Integer index = mIndex.get(device);
             if (index == null) {
                 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
-                index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT);
+                index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
             }
             return index.intValue();
         }
 
-        public synchronized void setLastAudibleIndex(int index, int device) {
-            // Apply change to all streams using this one as alias
-            // if changing volume of current device, also change volume of current
-            // device on aliased stream
-            boolean currentDevice = (device == getDeviceForStream(mStreamType));
-            int numStreamTypes = AudioSystem.getNumStreamTypes();
-            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                if (streamType != mStreamType &&
-                        mStreamVolumeAlias[streamType] == mStreamType) {
-                    int scaledIndex = rescaleIndex(index, mStreamType, streamType);
-                    mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device);
-                    if (currentDevice) {
-                        mStreamStates[streamType].setLastAudibleIndex(scaledIndex,
-                                                                   getDeviceForStream(streamType));
-                    }
-                }
-            }
-            mLastAudibleIndex.put(device, getValidIndex(index));
-        }
-
-        public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
-            setLastAudibleIndex(getIndex(device,
-                                         true  /* lastAudible */) + deltaIndex,
-                                device);
-        }
-
         public int getMaxIndex() {
             return mIndexMax;
         }
 
-        // only called by setAllIndexes() which is already synchronized
-        public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
-            if (lastAudible) {
-                return mLastAudibleIndex;
-            } else {
-                return mIndex;
-            }
-        }
-
-        public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
-            ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
-            Set set = indexes.entrySet();
+        public synchronized void setAllIndexes(VolumeStreamState srcStream) {
+            Set set = srcStream.mIndex.entrySet();
             Iterator i = set.iterator();
             while (i.hasNext()) {
                 Map.Entry entry = (Map.Entry)i.next();
@@ -2963,11 +2853,7 @@
                 int index = ((Integer)entry.getValue()).intValue();
                 index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
 
-                if (lastAudible) {
-                    setLastAudibleIndex(index, device);
-                } else {
-                    setIndex(index, device, false /* lastAudible */);
-                }
+                setIndex(index, device);
             }
         }
 
@@ -2978,12 +2864,6 @@
                 Map.Entry entry = (Map.Entry)i.next();
                 entry.setValue(mIndexMax);
             }
-            set = mLastAudibleIndex.entrySet();
-            i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                entry.setValue(mIndexMax);
-            }
         }
 
         public synchronized void mute(IBinder cb, boolean state) {
@@ -3002,7 +2882,7 @@
         private int getValidIndex(int index) {
             if (index < 0) {
                 return 0;
-            } else if (index > mIndexMax) {
+            } else if (mUseFixedVolume || index > mIndexMax) {
                 return mIndexMax;
             }
 
@@ -3019,6 +2899,7 @@
 
             // must be called while synchronized on parent VolumeStreamState
             public void mute(boolean state) {
+                boolean updateVolume = false;
                 if (state) {
                     if (mMuteCount == 0) {
                         // Register for client death notification
@@ -3027,22 +2908,10 @@
                             if (mICallback != null) {
                                 mICallback.linkToDeath(this, 0);
                             }
-                            mDeathHandlers.add(this);
+                            VolumeStreamState.this.mDeathHandlers.add(this);
                             // If the stream is not yet muted by any client, set level to 0
-                            if (muteCount() == 0) {
-                                Set set = mIndex.entrySet();
-                                Iterator i = set.iterator();
-                                while (i.hasNext()) {
-                                    Map.Entry entry = (Map.Entry)i.next();
-                                    int device = ((Integer)entry.getKey()).intValue();
-                                    setIndex(0, device, false /* lastAudible */);
-                                }
-                                sendMsg(mAudioHandler,
-                                        MSG_SET_ALL_VOLUMES,
-                                        SENDMSG_QUEUE,
-                                        0,
-                                        0,
-                                        VolumeStreamState.this, 0);
+                            if (!VolumeStreamState.this.isMuted()) {
+                                updateVolume = true;
                             }
                         } catch (RemoteException e) {
                             // Client has died!
@@ -3060,37 +2929,25 @@
                         mMuteCount--;
                         if (mMuteCount == 0) {
                             // Unregister from client death notification
-                            mDeathHandlers.remove(this);
+                            VolumeStreamState.this.mDeathHandlers.remove(this);
                             // mICallback can be 0 if muted by AudioService
                             if (mICallback != null) {
                                 mICallback.unlinkToDeath(this, 0);
                             }
-                            if (muteCount() == 0) {
-                                // If the stream is not muted any more, restore its volume if
-                                // ringer mode allows it
-                                if (!isStreamAffectedByRingerMode(mStreamType) ||
-                                        mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
-                                    Set set = mIndex.entrySet();
-                                    Iterator i = set.iterator();
-                                    while (i.hasNext()) {
-                                        Map.Entry entry = (Map.Entry)i.next();
-                                        int device = ((Integer)entry.getKey()).intValue();
-                                        setIndex(getIndex(device,
-                                                          true  /* lastAudible */),
-                                                 device,
-                                                 false  /* lastAudible */);
-                                    }
-                                    sendMsg(mAudioHandler,
-                                            MSG_SET_ALL_VOLUMES,
-                                            SENDMSG_QUEUE,
-                                            0,
-                                            0,
-                                            VolumeStreamState.this, 0);
-                                }
+                            if (!VolumeStreamState.this.isMuted()) {
+                                updateVolume = true;
                             }
                         }
                     }
                 }
+                if (updateVolume) {
+                    sendMsg(mAudioHandler,
+                            MSG_SET_ALL_VOLUMES,
+                            SENDMSG_QUEUE,
+                            0,
+                            0,
+                            VolumeStreamState.this, 0);
+                }
             }
 
             public void binderDied() {
@@ -3112,6 +2969,10 @@
             return count;
         }
 
+        private synchronized boolean isMuted() {
+            return muteCount() != 0;
+        }
+
         // only called by mute() which is already synchronized
         private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
             VolumeDeathHandler handler;
@@ -3144,14 +3005,6 @@
                 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
                              + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
             }
-            pw.print("\n   Last audible: ");
-            set = mLastAudibleIndex.entrySet();
-            i = set.iterator();
-            while (i.hasNext()) {
-                Map.Entry entry = (Map.Entry)i.next();
-                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
-                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
-            }
         }
     }
 
@@ -3199,8 +3052,8 @@
             sendMsg(mAudioHandler,
                     MSG_PERSIST_VOLUME,
                     SENDMSG_QUEUE,
-                    PERSIST_CURRENT|PERSIST_LAST_AUDIBLE,
                     device,
+                    0,
                     streamState,
                     PERSIST_DELAY);
 
@@ -3221,29 +3074,177 @@
             }
         }
 
-        private void persistVolume(VolumeStreamState streamState,
-                                   int persistType,
-                                   int device) {
-            if ((persistType & PERSIST_CURRENT) != 0) {
-                System.putIntForUser(mContentResolver,
-                          streamState.getSettingNameForDevice(false /* lastAudible */, device),
-                          (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10,
-                          UserHandle.USER_CURRENT);
+        private void persistVolume(VolumeStreamState streamState, int device) {
+            if (mUseFixedVolume) {
+                return;
             }
-            if ((persistType & PERSIST_LAST_AUDIBLE) != 0) {
-                System.putIntForUser(mContentResolver,
-                        streamState.getSettingNameForDevice(true /* lastAudible */, device),
-                        (streamState.getIndex(device, true  /* lastAudible */) + 5) / 10,
-                        UserHandle.USER_CURRENT);
-            }
+            System.putIntForUser(mContentResolver,
+                      streamState.getSettingNameForDevice(device),
+                      (streamState.getIndex(device) + 5)/ 10,
+                      UserHandle.USER_CURRENT);
         }
 
         private void persistRingerMode(int ringerMode) {
+            if (mUseFixedVolume) {
+                return;
+            }
             Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
         }
 
-        private void playSoundEffect(int effectType, int volume) {
+        private boolean onLoadSoundEffects() {
+            int status;
+
             synchronized (mSoundEffectsLock) {
+                if (!mBootCompleted) {
+                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
+                    return false;
+                }
+
+                if (mSoundPool != null) {
+                    return true;
+                }
+
+                loadTouchSoundAssets();
+
+                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
+                mSoundPoolCallBack = null;
+                mSoundPoolListenerThread = new SoundPoolListenerThread();
+                mSoundPoolListenerThread.start();
+                int attempts = 3;
+                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
+                    try {
+                        // Wait for mSoundPoolCallBack to be set by the other thread
+                        mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
+                    } catch (InterruptedException e) {
+                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
+                    }
+                }
+
+                if (mSoundPoolCallBack == null) {
+                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
+                    if (mSoundPoolLooper != null) {
+                        mSoundPoolLooper.quit();
+                        mSoundPoolLooper = null;
+                    }
+                    mSoundPoolListenerThread = null;
+                    mSoundPool.release();
+                    mSoundPool = null;
+                    return false;
+                }
+                /*
+                 * poolId table: The value -1 in this table indicates that corresponding
+                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
+                 * Once loaded, the value in poolId is the sample ID and the same
+                 * sample can be reused for another effect using the same file.
+                 */
+                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
+                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
+                    poolId[fileIdx] = -1;
+                }
+                /*
+                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
+                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
+                 * this indicates we have a valid sample loaded for this effect.
+                 */
+
+                int numSamples = 0;
+                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                    // Do not load sample if this effect uses the MediaPlayer
+                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
+                        continue;
+                    }
+                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
+                        String filePath = Environment.getRootDirectory()
+                                + SOUND_EFFECTS_PATH
+                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
+                        int sampleId = mSoundPool.load(filePath, 0);
+                        if (sampleId <= 0) {
+                            Log.w(TAG, "Soundpool could not load file: "+filePath);
+                        } else {
+                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
+                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
+                            numSamples++;
+                        }
+                    } else {
+                        SOUND_EFFECT_FILES_MAP[effect][1] =
+                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
+                    }
+                }
+                // wait for all samples to be loaded
+                if (numSamples > 0) {
+                    mSoundPoolCallBack.setSamples(poolId);
+
+                    attempts = 3;
+                    status = 1;
+                    while ((status == 1) && (attempts-- > 0)) {
+                        try {
+                            mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
+                            status = mSoundPoolCallBack.status();
+                        } catch (InterruptedException e) {
+                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
+                        }
+                    }
+                } else {
+                    status = -1;
+                }
+
+                if (mSoundPoolLooper != null) {
+                    mSoundPoolLooper.quit();
+                    mSoundPoolLooper = null;
+                }
+                mSoundPoolListenerThread = null;
+                if (status != 0) {
+                    Log.w(TAG,
+                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
+                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
+                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
+                        }
+                    }
+
+                    mSoundPool.release();
+                    mSoundPool = null;
+                }
+            }
+            return (status == 0);
+        }
+
+        /**
+         *  Unloads samples from the sound pool.
+         *  This method can be called to free some memory when
+         *  sound effects are disabled.
+         */
+        private void onUnloadSoundEffects() {
+            synchronized (mSoundEffectsLock) {
+                if (mSoundPool == null) {
+                    return;
+                }
+
+                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
+                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
+                    poolId[fileIdx] = 0;
+                }
+
+                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
+                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
+                        continue;
+                    }
+                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
+                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
+                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
+                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
+                    }
+                }
+                mSoundPool.release();
+                mSoundPool = null;
+            }
+        }
+
+        private void onPlaySoundEffect(int effectType, int volume) {
+            synchronized (mSoundEffectsLock) {
+
+                onLoadSoundEffects();
+
                 if (mSoundPool == null) {
                     return;
                 }
@@ -3256,11 +3257,13 @@
                 }
 
                 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
-                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f);
+                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
+                                        volFloat, volFloat, 0, 0, 1.0f);
                 } else {
                     MediaPlayer mediaPlayer = new MediaPlayer();
                     try {
-                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]];
+                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
+                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
                         mediaPlayer.setDataSource(filePath);
                         mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
                         mediaPlayer.prepare();
@@ -3330,10 +3333,13 @@
                     break;
 
                 case MSG_PERSIST_VOLUME:
-                    persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
+                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
                     break;
 
                 case MSG_PERSIST_MASTER_VOLUME:
+                    if (mUseFixedVolume) {
+                        return;
+                    }
                     Settings.System.putFloatForUser(mContentResolver,
                                                     Settings.System.VOLUME_MASTER,
                                                     (float)msg.arg1 / (float)1000.0,
@@ -3341,6 +3347,9 @@
                     break;
 
                 case MSG_PERSIST_MASTER_VOLUME_MUTE:
+                    if (mUseFixedVolume) {
+                        return;
+                    }
                     Settings.System.putIntForUser(mContentResolver,
                                                  Settings.System.VOLUME_MASTER_MUTE,
                                                  msg.arg1,
@@ -3429,12 +3438,25 @@
                     AudioSystem.setParameters("restarting=false");
                     break;
 
+                case MSG_UNLOAD_SOUND_EFFECTS:
+                    onUnloadSoundEffects();
+                    break;
+
                 case MSG_LOAD_SOUND_EFFECTS:
-                    loadSoundEffects();
+                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
+                    // can take several dozens of milliseconds to complete
+                    boolean loaded = onLoadSoundEffects();
+                    if (msg.obj != null) {
+                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
+                        synchronized (reply) {
+                            reply.mStatus = loaded ? 0 : -1;
+                            reply.notify();
+                        }
+                    }
                     break;
 
                 case MSG_PLAY_SOUND_EFFECT:
-                    playSoundEffect(msg.arg1, msg.arg2);
+                    onPlaySoundEffect(msg.arg1, msg.arg2);
                     break;
 
                 case MSG_BTA2DP_DOCK_TIMEOUT:
@@ -3508,6 +3530,13 @@
                     onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
                             (IRemoteVolumeObserver)msg.obj /* rvo */);
                     break;
+                case MSG_RCC_NEW_PLAYBACK_STATE:
+                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */, msg.arg2 /* state */,
+                            (RccPlaybackState)msg.obj /* newState */);
+                    break;
+                case MSG_RCC_SEEK_REQUEST:
+                    onSetRemoteControlClientPlaybackPosition(msg.arg1 /* generationId */,
+                            ((Long)msg.obj).longValue() /* timeMs */);
 
                 case MSG_SET_RSX_CONNECTION_STATE:
                     onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/);
@@ -3532,6 +3561,10 @@
                 case MSG_PROMOTE_RCC:
                     onPromoteRcc(msg.arg1);
                     break;
+
+                case MSG_BROADCAST_BT_CONNECTION_STATE:
+                    onBroadcastScoConnectionState(msg.arg1);
+                    break;
             }
         }
     }
@@ -3978,7 +4011,7 @@
                 }
             } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
                 mBootCompleted = true;
-                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP,
+                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
                         0, 0, null, 0);
 
                 mKeyguardManager =
@@ -4006,19 +4039,26 @@
                         0,
                         null,
                         SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
-            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
+            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                     // a package is being removed, not replaced
                     String packageName = intent.getData().getSchemeSpecificPart();
                     if (packageName != null) {
-                        removeMediaButtonReceiverForPackage(packageName);
+                        cleanupMediaButtonReceiverForPackage(packageName, true);
                     }
                 }
+            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
+                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
+                String packageName = intent.getData().getSchemeSpecificPart();
+                if (packageName != null) {
+                    cleanupMediaButtonReceiverForPackage(packageName, false);
+                }
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 AudioSystem.setParameters("screen_state=on");
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 AudioSystem.setParameters("screen_state=off");
-            } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) {
+            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                 handleConfigurationChanged(context);
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                 // attempt to stop music playback for background user
@@ -4187,7 +4227,7 @@
      * Helper function:
      * Called synchronized on mAudioFocusLock
      * Remove a focus listener from the focus stack.
-     * @param focusListenerToRemove the focus listener
+     * @param clientToRemove the focus listener
      * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
      *   focus, notify the next item in the stack it gained focus.
      */
@@ -4293,7 +4333,7 @@
     }
 
 
-    /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
+    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
     public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
             IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
         Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
@@ -4366,7 +4406,7 @@
         return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
     }
 
-    /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */
+    /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener)  */
     public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
         Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
         try {
@@ -4677,6 +4717,9 @@
         }
     };
 
+    /**
+     * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
+     */
     private final Object mCurrentRcLock = new Object();
     /**
      * The one remote control client which will receive a request for display information.
@@ -4704,8 +4747,8 @@
      * remote control stack if necessary.
      */
     private class RcClientDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
-        private PendingIntent mMediaIntent;
+        final private IBinder mCb; // To be notified of client's death
+        final private PendingIntent mMediaIntent;
 
         RcClientDeathHandler(IBinder cb, PendingIntent pi) {
             mCb = cb;
@@ -4764,18 +4807,73 @@
      */
     private boolean mHasRemotePlayback;
 
-    private static class RemoteControlStackEntry {
+    private static class RccPlaybackState {
+        public int mState;
+        public long mPositionMs;
+        public float mSpeed;
+
+        public RccPlaybackState(int state, long positionMs, float speed) {
+            mState = state;
+            mPositionMs = positionMs;
+            mSpeed = speed;
+        }
+
+        public void reset() {
+            mState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
+            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
+        }
+
+        @Override
+        public String toString() {
+            return stateToString() + ", "
+                    + ((mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) ?
+                            "PLAYBACK_POSITION_INVALID ," : String.valueOf(mPositionMs)) + "ms ,"
+                    + mSpeed + "X";
+        }
+
+        private String stateToString() {
+            switch (mState) {
+                case RemoteControlClient.PLAYSTATE_NONE:
+                    return "PLAYSTATE_NONE";
+                case RemoteControlClient.PLAYSTATE_STOPPED:
+                    return "PLAYSTATE_STOPPED";
+                case RemoteControlClient.PLAYSTATE_PAUSED:
+                    return "PLAYSTATE_PAUSED";
+                case RemoteControlClient.PLAYSTATE_PLAYING:
+                    return "PLAYSTATE_PLAYING";
+                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+                    return "PLAYSTATE_FAST_FORWARDING";
+                case RemoteControlClient.PLAYSTATE_REWINDING:
+                    return "PLAYSTATE_REWINDING";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                    return "PLAYSTATE_SKIPPING_FORWARDS";
+                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                    return "PLAYSTATE_SKIPPING_BACKWARDS";
+                case RemoteControlClient.PLAYSTATE_BUFFERING:
+                    return "PLAYSTATE_BUFFERING";
+                case RemoteControlClient.PLAYSTATE_ERROR:
+                    return "PLAYSTATE_ERROR";
+                default:
+                    return "[invalid playstate]";
+            }
+        }
+    }
+
+    private static class RemoteControlStackEntry implements DeathRecipient {
         public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+        final public AudioService mService;
         /**
          * The target for the ACTION_MEDIA_BUTTON events.
          * Always non null.
          */
-        public PendingIntent mMediaIntent;
+        final public PendingIntent mMediaIntent;
         /**
          * The registered media button event receiver.
          * Always non null.
          */
-        public ComponentName mReceiverComponent;
+        final public ComponentName mReceiverComponent;
+        public IBinder mToken;
         public String mCallingPackageName;
         public int mCallingUid;
         /**
@@ -4792,7 +4890,7 @@
         public int mPlaybackVolumeMax;
         public int mPlaybackVolumeHandling;
         public int mPlaybackStream;
-        public int mPlaybackState;
+        public RccPlaybackState mPlaybackState;
         public IRemoteVolumeObserver mRemoteVolumeObs;
 
         public void resetPlaybackInfo() {
@@ -4801,19 +4899,37 @@
             mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
             mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
             mPlaybackStream = AudioManager.STREAM_MUSIC;
-            mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mPlaybackState.reset();
             mRemoteVolumeObs = null;
         }
 
-        /** precondition: mediaIntent != null, eventReceiver != null */
-        public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
+        /** precondition: mediaIntent != null */
+        public RemoteControlStackEntry(AudioService service, PendingIntent mediaIntent,
+                ComponentName eventReceiver, IBinder token) {
+            mService = service;
             mMediaIntent = mediaIntent;
             mReceiverComponent = eventReceiver;
+            mToken = token;
             mCallingUid = -1;
             mRcClient = null;
             mRccId = ++sLastRccId;
+            mPlaybackState = new RccPlaybackState(
+                    RemoteControlClient.PLAYSTATE_STOPPED,
+                    RemoteControlClient.PLAYBACK_POSITION_INVALID,
+                    RemoteControlClient.PLAYBACK_SPEED_1X);
 
             resetPlaybackInfo();
+            if (mToken != null) {
+                try {
+                    mToken.linkToDeath(this, 0);
+                } catch (RemoteException e) {
+                    mService.mAudioHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mService.unregisterMediaButtonIntent(mMediaIntent);
+                        }
+                    });
+                }
+            }
         }
 
         public void unlinkToRcClientDeath() {
@@ -4829,9 +4945,22 @@
             }
         }
 
+        public void destroy() {
+            unlinkToRcClientDeath();
+            if (mToken != null) {
+                mToken.unlinkToDeath(this, 0);
+                mToken = null;
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mService.unregisterMediaButtonIntent(mMediaIntent);
+        }
+
         @Override
         protected void finalize() throws Throwable {
-            unlinkToRcClientDeath();// unlink exception handled inside method
+            destroy(); // unlink exception handled inside method
             super.finalize();
         }
     }
@@ -4890,7 +5019,9 @@
                         "  -- vol: " + rcse.mPlaybackVolume +
                         "  -- volMax: " + rcse.mPlaybackVolumeMax +
                         "  -- volObs: " + rcse.mRemoteVolumeObs);
-
+            }
+            synchronized(mCurrentRcLock) {
+                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
             }
         }
         synchronized (mMainRemote) {
@@ -4908,14 +5039,32 @@
 
     /**
      * Helper function:
+     * Display in the log the current entries in the list of remote control displays
+     */
+    private void dumpRCDList(PrintWriter pw) {
+        pw.println("\nRemote Control Display list entries:");
+        synchronized(mRCStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                pw.println("  IRCD: " + di.mRcDisplay +
+                        "  -- w:" + di.mArtworkExpectedWidth +
+                        "  -- h:" + di.mArtworkExpectedHeight);
+            }
+        }
+    }
+
+    /**
+     * Helper function:
      * Remove any entry in the remote control stack that has the same package name as packageName
      * Pre-condition: packageName != null
      */
-    private void removeMediaButtonReceiverForPackage(String packageName) {
+    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
         synchronized(mRCStack) {
             if (mRCStack.empty()) {
                 return;
             } else {
+                final PackageManager pm = mContext.getPackageManager();
                 RemoteControlStackEntry oldTop = mRCStack.peek();
                 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
                 // iterate over the stack entries
@@ -4923,10 +5072,19 @@
                 //  evaluated it, traversal order doesn't matter here)
                 while(stackIterator.hasNext()) {
                     RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
-                    if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
+                    if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
                         // a stack entry is from the package being removed, remove it from the stack
                         stackIterator.remove();
-                        rcse.unlinkToRcClientDeath();
+                        rcse.destroy();
+                    } else if (rcse.mReceiverComponent != null) {
+                        try {
+                            // Check to see if this receiver still exists.
+                            pm.getReceiverInfo(rcse.mReceiverComponent, 0);
+                        } catch (PackageManager.NameNotFoundException e) {
+                            // Not found -- remove it!
+                            stackIterator.remove();
+                            rcse.destroy();
+                        }
                     }
                 }
                 if (mRCStack.empty()) {
@@ -4936,10 +5094,14 @@
                                     null));
                 } else if (oldTop != mRCStack.peek()) {
                     // the top of the stack has changed, save it in the system settings
-                    // by posting a message to persist it
-                    mAudioHandler.sendMessage(
-                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
-                                    mRCStack.peek().mReceiverComponent));
+                    // by posting a message to persist it; only do this however if it has
+                    // a concrete component name (is not a transient registration)
+                    RemoteControlStackEntry rcse = mRCStack.peek();
+                    if (rcse.mReceiverComponent != null) {
+                        mAudioHandler.sendMessage(
+                                mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+                                        rcse.mReceiverComponent));
+                    }
                 }
             }
         }
@@ -4954,6 +5116,10 @@
                 Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
         if ((null != receiverName) && !receiverName.isEmpty()) {
             ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
+            if (eventReceiver == null) {
+                // an invalid name was persisted
+                return;
+            }
             // construct a PendingIntent targeted to the restored component name
             // for the media button and register it
             Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
@@ -4961,7 +5127,7 @@
             mediaButtonIntent.setComponent(eventReceiver);
             PendingIntent pi = PendingIntent.getBroadcast(mContext,
                     0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
-            registerMediaButtonIntent(pi, eventReceiver);
+            registerMediaButtonIntent(pi, eventReceiver, null);
         }
     }
 
@@ -4969,9 +5135,10 @@
      * Helper function:
      * Set the new remote control receiver at the top of the RC focus stack.
      * Called synchronized on mAudioFocusLock, then mRCStack
-     * precondition: mediaIntent != null, target != null
+     * precondition: mediaIntent != null
      */
-    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target) {
+    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target,
+            IBinder token) {
         // already at top of stack?
         if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
             return;
@@ -4993,13 +5160,15 @@
             Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
         }
         if (!wasInsideStack) {
-            rcse = new RemoteControlStackEntry(mediaIntent, target);
+            rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
         }
         mRCStack.push(rcse); // rcse is never null
 
         // post message to persist the default media button receiver
-        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
-                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+        if (target != null) {
+            mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
+                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+        }
     }
 
     /**
@@ -5013,7 +5182,7 @@
             for (int index = mRCStack.size()-1; index >= 0; index--) {
                 final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
                 if (rcse.mMediaIntent.equals(pi)) {
-                    rcse.unlinkToRcClientDeath();
+                    rcse.destroy();
                     // ok to remove element while traversing the stack since we're leaving the loop
                     mRCStack.removeElementAt(index);
                     break;
@@ -5044,16 +5213,20 @@
      */
     private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
             PendingIntent newMediaIntent, boolean clearing) {
-        // NOTE: Only one IRemoteControlDisplay supported in this implementation
-        if (mRcDisplay != null) {
-            try {
-                mRcDisplay.setCurrentClientId(
-                        newClientGeneration, newMediaIntent, clearing);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
-                // if we had a display before, stop monitoring its death
-                rcDisplay_stopDeathMonitor_syncRcStack();
-                mRcDisplay = null;
+        synchronized(mRCStack) {
+            if (mRcDisplays.size() > 0) {
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = displayIterator.next();
+                    try {
+                        di.mRcDisplay.setCurrentClientId(
+                                newClientGeneration, newMediaIntent, clearing);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
+                        di.release();
+                        displayIterator.remove();
+                    }
+                }
             }
         }
     }
@@ -5071,7 +5244,7 @@
                 try {
                     se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e);
+                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
                     stackIterator.remove();
                     se.unlinkToRcClientDeath();
                 }
@@ -5082,7 +5255,7 @@
     /**
      * Update the displays and clients with the new "focused" client generation and name
      * @param newClientGeneration the new generation value matching a client update
-     * @param newClientEventReceiver the media button event receiver associated with the client.
+     * @param newMediaIntent the media button event receiver associated with the client.
      *    May be null, which implies there is no registered media button event receiver.
      * @param clearing true if the new client generation value maps to a remote control update
      *    where the display should be cleared.
@@ -5129,8 +5302,7 @@
 
                     // tell the current client that it needs to send info
                     try {
-                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
-                                flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
+                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Current valid remote client is dead: "+e);
                         mCurrentRcClient = null;
@@ -5296,14 +5468,15 @@
 
     /**
      * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
-     * precondition: mediaIntent != null, target != null
+     * precondition: mediaIntent != null
      */
-    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
+    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
+            IBinder token) {
         Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
 
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
-                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver);
+                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token);
                 // new RC client, assume every type of information shall be queried
                 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
             }
@@ -5314,7 +5487,7 @@
      * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
      * precondition: mediaIntent != null, eventReceiver != null
      */
-    public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver)
+    public void unregisterMediaButtonIntent(PendingIntent mediaIntent)
     {
         Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
 
@@ -5394,13 +5567,9 @@
                             rccId = rcse.mRccId;
 
                             // there is a new (non-null) client:
-                            // 1/ give the new client the current display (if any)
-                            if (mRcDisplay != null) {
-                                try {
-                                    rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
-                                } catch (RemoteException e) {
-                                    Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
-                                }
+                            // 1/ give the new client the displays (if any)
+                            if (mRcDisplays.size() > 0) {
+                                plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
                             }
                             // 2/ monitor the new client's death
                             IBinder b = rcse.mRcClient.asBinder();
@@ -5470,102 +5639,141 @@
         }
     }
 
-    /**
-     * The remote control displays.
-     * Access synchronized on mRCStack
-     * NOTE: Only one IRemoteControlDisplay supported in this implementation
-     */
-    private IRemoteControlDisplay mRcDisplay;
-    private RcDisplayDeathHandler mRcDisplayDeathHandler;
-    private int mArtworkExpectedWidth = -1;
-    private int mArtworkExpectedHeight = -1;
-    /**
-     * Inner class to monitor remote control display deaths, and unregister them from the list
-     * of displays if necessary.
-     */
-    private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
-        private IBinder mCb; // To be notified of client's death
 
-        public RcDisplayDeathHandler(IBinder b) {
-            if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b);
-            mCb = b;
+    /**
+     * A class to encapsulate all the information about a remote control display.
+     * After instanciation, init() must always be called before the object is added in the list
+     * of displays.
+     * Before being removed from the list of displays, release() must always be called (otherwise
+     * it will leak death handlers).
+     */
+    private class DisplayInfoForServer implements IBinder.DeathRecipient {
+        /** may never be null */
+        private IRemoteControlDisplay mRcDisplay;
+        private IBinder mRcDisplayBinder;
+        private int mArtworkExpectedWidth = -1;
+        private int mArtworkExpectedHeight = -1;
+
+        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
+            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
+            mRcDisplay = rcd;
+            mRcDisplayBinder = rcd.asBinder();
+            mArtworkExpectedWidth = w;
+            mArtworkExpectedHeight = h;
+        }
+
+        public boolean init() {
+            try {
+                mRcDisplayBinder.linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                // remote control display is DOA, disqualify it
+                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
+                return false;
+            }
+            return true;
+        }
+
+        public void release() {
+            try {
+                mRcDisplayBinder.unlinkToDeath(this, 0);
+            } catch (java.util.NoSuchElementException e) {
+                // not much we can do here, the display should have been unregistered anyway
+                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
+            }
         }
 
         public void binderDied() {
             synchronized(mRCStack) {
-                Log.w(TAG, "RemoteControl: display died");
-                mRcDisplay = null;
+                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
+                // remove the display from the list
+                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+                while (displayIterator.hasNext()) {
+                    final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                    if (di.mRcDisplay == mRcDisplay) {
+                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
+                        displayIterator.remove();
+                        return;
+                    }
+                }
             }
         }
-
-        public void unlinkToRcDisplayDeath() {
-            if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb);
-            try {
-                mCb.unlinkToDeath(this, 0);
-            } catch (java.util.NoSuchElementException e) {
-                // not much we can do here, the display was being unregistered anyway
-                Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()");
-                e.printStackTrace();
-            }
-        }
-
-    }
-
-    private void rcDisplay_stopDeathMonitor_syncRcStack() {
-        if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
-            // we had a display before, stop monitoring its death
-            mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
-        }
     }
 
-    private void rcDisplay_startDeathMonitor_syncRcStack() {
-        if (mRcDisplay != null) {
-            // new non-null display, monitor its death
-            IBinder b = mRcDisplay.asBinder();
-            mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
+    /**
+     * The remote control displays.
+     * Access synchronized on mRCStack
+     */
+    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
+
+    /**
+     * Plug each registered display into the specified client
+     * @param rcc, guaranteed non null
+     */
+    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
             try {
-                b.linkToDeath(mRcDisplayDeathHandler, 0);
+                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
+                        di.mArtworkExpectedHeight);
             } catch (RemoteException e) {
-                // remote control display is DOA, disqualify it
-                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b);
-                mRcDisplay = null;
+                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
             }
         }
     }
 
     /**
+     * Is the remote control display interface already registered
+     * @param rcd
+     * @return true if the IRemoteControlDisplay is already in the list of displays
+     */
+    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
+        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+        while (displayIterator.hasNext()) {
+            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Register an IRemoteControlDisplay.
      * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
      * at the top of the stack to update the new display with its information.
-     * Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
+     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
      * @param rcd the IRemoteControlDisplay to register. No effect if null.
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
      */
-    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
+    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
         if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
-                if ((mRcDisplay == rcd) || (rcd == null)) {
+                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
                     return;
                 }
-                // if we had a display before, stop monitoring its death
-                rcDisplay_stopDeathMonitor_syncRcStack();
-                mRcDisplay = rcd;
-                // new display, start monitoring its death
-                rcDisplay_startDeathMonitor_syncRcStack();
+                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
+                if (!di.init()) {
+                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
+                    return;
+                }
+                // add RCD to list of displays
+                mRcDisplays.add(di);
 
-                // let all the remote control clients know there is a new display, so the remote
-                //   control stack traversal order doesn't matter.
-                // No need to unplug the previous because we only support one display
-                // and the clients don't track the death of the display
+                // let all the remote control clients know there is a new display (so the remote
+                //   control stack traversal order doesn't matter).
                 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
                 while(stackIterator.hasNext()) {
                     RemoteControlStackEntry rcse = stackIterator.next();
                     if(rcse.mRcClient != null) {
                         try {
-                            rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
+                            rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
                         } catch (RemoteException e) {
-                            Log.e(TAG, "Error connecting remote control display to client: " + e);
-                            e.printStackTrace();
+                            Log.e(TAG, "Error connecting RCD to client: ", e);
                         }
                     }
                 }
@@ -5578,44 +5786,118 @@
 
     /**
      * Unregister an IRemoteControlDisplay.
-     * Since only one IRemoteControlDisplay is supported, this has no effect if the one to
-     *    unregister is not the current one.
+     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
+     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
      * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
      */
     public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
         if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
         synchronized(mRCStack) {
-            // only one display here, so you can only unregister the current display
-            if ((rcd == null) || (rcd != mRcDisplay)) {
-                if (DEBUG_RC) Log.w(TAG, "    trying to unregister unregistered RCD");
+            if (rcd == null) {
                 return;
             }
-            // if we had a display before, stop monitoring its death
-            rcDisplay_stopDeathMonitor_syncRcStack();
-            mRcDisplay = null;
 
-            // disconnect this remote control display from all the clients, so the remote
-            //   control stack traversal order doesn't matter
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                if(rcse.mRcClient != null) {
-                    try {
-                        rcse.mRcClient.unplugRemoteControlDisplay(rcd);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error disconnecting remote control display to client: " + e);
-                        e.printStackTrace();
+            boolean displayWasPluggedIn = false;
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext() && !displayWasPluggedIn) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    displayWasPluggedIn = true;
+                    di.release();
+                    displayIterator.remove();
+                }
+            }
+
+            if (displayWasPluggedIn) {
+                // disconnect this remote control display from all the clients, so the remote
+                //   control stack traversal order doesn't matter
+                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.unplugRemoteControlDisplay(rcd);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
+                        }
+                    }
+                }
+            } else {
+                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
+            }
+        }
+    }
+
+    /**
+     * Update the size of the artwork used by an IRemoteControlDisplay.
+     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
+     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+        synchronized(mRCStack) {
+            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
+            boolean artworkSizeUpdate = false;
+            while (displayIterator.hasNext() && !artworkSizeUpdate) {
+                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
+                        di.mArtworkExpectedWidth = w;
+                        di.mArtworkExpectedHeight = h;
+                        artworkSizeUpdate = true;
+                    }
+                }
+            }
+            if (artworkSizeUpdate) {
+                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
+                // stack traversal order doesn't matter
+                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    final RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
+                        }
                     }
                 }
             }
         }
     }
 
-    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
+    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        // ignore position change requests if invalid generation ID
         synchronized(mRCStack) {
-            // NOTE: Only one IRemoteControlDisplay supported in this implementation
-            mArtworkExpectedWidth = w;
-            mArtworkExpectedHeight = h;
+            synchronized(mCurrentRcLock) {
+                if (mCurrentRcClientGen != generationId) {
+                    return;
+                }
+            }
+        }
+        // discard any unprocessed seek request in the message queue, and replace with latest
+        sendMsg(mAudioHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
+                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
+    }
+
+    public void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
+        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
+                ", timeMs=" + timeMs + ")");
+        synchronized(mRCStack) {
+            synchronized(mCurrentRcLock) {
+                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
+                    // tell the current client to seek to the requested location
+                    try {
+                        mCurrentRcClient.seekTo(generationId, timeMs);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Current valid remote client is dead: "+e);
+                        mCurrentRcClient = null;
+                    }
+                }
+            }
         }
     }
 
@@ -5670,21 +5952,6 @@
                             case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
                                 rcse.mPlaybackStream = value;
                                 break;
-                            case RemoteControlClient.PLAYBACKINFO_PLAYSTATE:
-                                rcse.mPlaybackState = value;
-                                synchronized (mMainRemote) {
-                                    if (rccId == mMainRemote.mRccId) {
-                                        mMainRemoteIsActive = isPlaystateActive(value);
-                                        postReevaluateRemote();
-                                    }
-                                }
-                                // an RCC moving to a "playing" state should become the media button
-                                //   event receiver so it can be controlled, without requiring the
-                                //   app to re-register its receiver
-                                if (isPlaystateActive(value)) {
-                                    postPromoteRcc(rccId);
-                                }
-                                break;
                             default:
                                 Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
                                 break;
@@ -5694,7 +5961,45 @@
                 }//for
             } catch (ArrayIndexOutOfBoundsException e) {
                 // not expected to happen, indicates improper concurrent modification
-                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
+            }
+        }
+    }
+
+    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
+        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
+                rccId /* arg1 */, state /* arg2 */,
+                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
+    }
+
+    public void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
+        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
+                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
+        synchronized(mRCStack) {
+            // iterating from top of stack as playback information changes are more likely
+            //   on entries at the top of the remote control stack
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mPlaybackState = newState;
+                        synchronized (mMainRemote) {
+                            if (rccId == mMainRemote.mRccId) {
+                                mMainRemoteIsActive = isPlaystateActive(state);
+                                postReevaluateRemote();
+                            }
+                        }
+                        // an RCC moving to a "playing" state should become the media button
+                        //   event receiver so it can be controlled, without requiring the
+                        //   app to re-register its receiver
+                        if (isPlaystateActive(state)) {
+                            postPromoteRcc(rccId);
+                        }
+                    }
+                }//for
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
             }
         }
     }
@@ -5738,7 +6043,7 @@
                 for (int index = mRCStack.size()-1; index >= 0; index--) {
                     final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
                     if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
-                            && isPlaystateActive(rcse.mPlaybackState)
+                            && isPlaystateActive(rcse.mPlaybackState.mState)
                             && (rcse.mPlaybackStream == streamType)) {
                         if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
                                 + ", vol =" + rcse.mPlaybackVolume);
@@ -5969,10 +6274,7 @@
                             mRingerModeAffectedStreams &=
                                     ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
                         } else {
-                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
-                                            false /*lastAudible*/);
-                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
-                                            true /*lastAudible*/);
+                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
                             mRingerModeAffectedStreams |=
                                     (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
                         }
@@ -6118,7 +6420,6 @@
 
     private void enforceSafeMediaVolume() {
         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
-        boolean lastAudible = (streamState.muteCount() != 0);
         int devices = mSafeMediaVolumeDevices;
         int i = 0;
 
@@ -6127,27 +6428,16 @@
             if ((device & devices) == 0) {
                 continue;
             }
-            int index = streamState.getIndex(device, lastAudible);
+            int index = streamState.getIndex(device);
             if (index > mSafeMediaVolumeIndex) {
-                if (lastAudible) {
-                    streamState.setLastAudibleIndex(mSafeMediaVolumeIndex, device);
-                    sendMsg(mAudioHandler,
-                            MSG_PERSIST_VOLUME,
-                            SENDMSG_QUEUE,
-                            PERSIST_LAST_AUDIBLE,
-                            device,
-                            streamState,
-                            PERSIST_DELAY);
-                } else {
-                    streamState.setIndex(mSafeMediaVolumeIndex, device, true);
-                    sendMsg(mAudioHandler,
-                            MSG_SET_DEVICE_VOLUME,
-                            SENDMSG_QUEUE,
-                            device,
-                            0,
-                            streamState,
-                            0);
-                }
+                streamState.setIndex(mSafeMediaVolumeIndex, device);
+                sendMsg(mAudioHandler,
+                        MSG_SET_DEVICE_VOLUME,
+                        SENDMSG_QUEUE,
+                        device,
+                        0,
+                        streamState,
+                        0);
             }
             devices &= ~device;
         }
@@ -6218,6 +6508,7 @@
         dumpFocusStack(pw);
         dumpRCStack(pw);
         dumpRCCStack(pw);
+        dumpRCDList(pw);
         dumpStreamStates(pw);
         dumpRingerMode(pw);
         pw.println("\nAudio routes:");
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index cd50de4..399eb7b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -791,7 +791,7 @@
      *    {@link #ERROR_INVALID_OPERATION}
      */
     public int setPlaybackRate(int sampleRateInHz) {
-        if (mState == STATE_UNINITIALIZED) {
+        if (mState != STATE_INITIALIZED) {
             return ERROR_INVALID_OPERATION;
         }
         if (sampleRateInHz <= 0) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ea99069..13f6c02 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -120,22 +120,61 @@
     oneway void dispatchMediaKeyEvent(in KeyEvent keyEvent);
     void dispatchMediaKeyEventUnderWakelock(in KeyEvent keyEvent);
 
-    oneway void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c);
-    oneway void unregisterMediaButtonIntent(in PendingIntent pi,  in ComponentName c);
+           void registerMediaButtonIntent(in PendingIntent pi, in ComponentName c, IBinder token);
+    oneway void unregisterMediaButtonIntent(in PendingIntent pi);
 
     oneway void registerMediaButtonEventReceiverForCalls(in ComponentName c);
     oneway void unregisterMediaButtonEventReceiverForCalls();
 
-    int registerRemoteControlClient(in PendingIntent mediaIntent,
-           in IRemoteControlClient rcClient, in String callingPackageName);
-    oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
-           in IRemoteControlClient rcClient);
-
-    oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd);
+    /**
+     * Register an IRemoteControlDisplay.
+     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
+     * at the top of the stack to update the new display with its information.
+     * @param rcd the IRemoteControlDisplay to register. No effect if null.
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
+    oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
+    /**
+     * Unregister an IRemoteControlDisplay.
+     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
+     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
+     */
     oneway void unregisterRemoteControlDisplay(in IRemoteControlDisplay rcd);
+    /**
+     * Update the size of the artwork used by an IRemoteControlDisplay.
+     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
+     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
+     *   display doesn't need to receive artwork.
+     */
     oneway void remoteControlDisplayUsesBitmapSize(in IRemoteControlDisplay rcd, int w, int h);
+    /**
+     * Request the user of a RemoteControlClient to seek to the given playback position.
+     * @param generationId the RemoteControlClient generation counter for which this request is
+     *         issued. Requests for an older generation than current one will be ignored.
+     * @param timeMs the time in ms to seek to, must be positive.
+     */
+     void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
+
+    /**
+     * Do not use directly, use instead
+     *     {@link android.media.AudioManager#registerRemoteControlClient(RemoteControlClient)}
+     */
+    int registerRemoteControlClient(in PendingIntent mediaIntent,
+            in IRemoteControlClient rcClient, in String callingPackageName);
+    /**
+     * Do not use directly, use instead
+     *     {@link android.media.AudioManager#unregisterRemoteControlClient(RemoteControlClient)}
+     */
+    oneway void unregisterRemoteControlClient(in PendingIntent mediaIntent,
+            in IRemoteControlClient rcClient);
 
     oneway void setPlaybackInfoForRcc(int rccId, int what, int value);
+    void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed);
            int  getRemoteStreamMaxVolume();
            int  getRemoteStreamVolume();
     oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index 0fbba20..e4cee06 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -34,18 +34,18 @@
      *   parameters are valid.
      * @param generationId
      * @param infoFlags
-     * @param artWidth if > 0, artHeight must be > 0 too.
-     * @param artHeight
      * FIXME: is infoFlags required? since the RCC pushes info, this might always be called
      *        with RC_INFO_ALL
      */
-    void onInformationRequested(int generationId, int infoFlags, int artWidth, int artHeight);
+    void onInformationRequested(int generationId, int infoFlags);
 
     /**
      * Sets the generation counter of the current client that is displayed on the remote control.
      */
     void setCurrentClientGenerationId(int clientGeneration);
 
-    void   plugRemoteControlDisplay(IRemoteControlDisplay rcd);
+    void   plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h);
     void unplugRemoteControlDisplay(IRemoteControlDisplay rcd);
+    void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
+    void seekTo(int clientGeneration, long timeMs);
 }
\ No newline at end of file
diff --git a/media/java/android/media/IRemoteControlDisplay.aidl b/media/java/android/media/IRemoteControlDisplay.aidl
index 204de3c..c70889c 100644
--- a/media/java/android/media/IRemoteControlDisplay.aidl
+++ b/media/java/android/media/IRemoteControlDisplay.aidl
@@ -40,9 +40,19 @@
     void setCurrentClientId(int clientGeneration, in PendingIntent clientMediaIntent,
             boolean clearing);
 
-    void setPlaybackState(int generationId, int state, long stateChangeTimeMs);
+    void setPlaybackState(int generationId, int state, long stateChangeTimeMs, long currentPosMs,
+            float speed);
 
-    void setTransportControlFlags(int generationId, int transportControlFlags);
+    /**
+     * Sets the transport control flags and playback position capabilities of a client.
+     * @param generationId the current generation ID as known by this client
+     * @param transportControlFlags bitmask of the transport controls this client supports, see
+     *         {@link RemoteControlClient#setTransportControlFlags(int)}
+     * @param posCapabilities a bit mask for playback position capabilities, see
+     *         {@link RemoteControlClient#MEDIA_POSITION_READABLE} and
+     *         {@link RemoteControlClient#MEDIA_POSITION_WRITABLE}
+     */
+    void setTransportControlInfo(int generationId, int transportControlFlags, int posCapabilities);
 
     void setMetadata(int generationId, in Bundle metadata);
 
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index e155385..45a8b99 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -22,6 +22,7 @@
 import android.media.MediaFormat;
 import android.view.Surface;
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Map;
 
 /**
@@ -263,12 +264,11 @@
             Surface surface, MediaCrypto crypto, int flags);
 
     /**
-     * Requests a Surface to use instead of input buffers.  This may only be called after
-     * {@link #configure} and before {@link #start}.
+     * Requests a Surface to use as the input to an encoder, in place of input buffers.  This
+     * may only be called after {@link #configure} and before {@link #start}.
      * <p>
      * The application is responsible for calling release() on the Surface when
      * done.
-     * @hide -- TODO(fadden): make this public before release
      */
     public native final Surface createInputSurface();
 
@@ -396,6 +396,27 @@
          * see {@link #CRYPTO_MODE_UNENCRYPTED} and {@link #CRYPTO_MODE_AES_CTR}.
          */
         public int mode;
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append(numSubSamples + " subsamples, key [");
+            String hexdigits = "0123456789abcdef";
+            for (int i = 0; i < key.length; i++) {
+                builder.append(hexdigits.charAt((key[i] & 0xf0) >> 4));
+                builder.append(hexdigits.charAt(key[i] & 0x0f));
+            }
+            builder.append("], iv [");
+            for (int i = 0; i < key.length; i++) {
+                builder.append(hexdigits.charAt((iv[i] & 0xf0) >> 4));
+                builder.append(hexdigits.charAt(iv[i] & 0x0f));
+            }
+            builder.append("], clear ");
+            builder.append(Arrays.toString(numBytesOfClearData));
+            builder.append(", encrypted ");
+            builder.append(Arrays.toString(numBytesOfEncryptedData));
+            return builder.toString();
+        }
     };
 
     /**
@@ -471,7 +492,6 @@
      * Signals end-of-stream on input.  Equivalent to submitting an empty buffer with
      * {@link #BUFFER_FLAG_END_OF_STREAM} set.  This may only be used with
      * encoders receiving input from a Surface created by {@link #createInputSurface}.
-     * @hide -- TODO(fadden): make this public before release
      */
     public native final void signalEndOfInputStream();
 
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 6c1b87a..1501c79 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -93,8 +93,9 @@
         public final static int COLOR_Format24BitABGR6666           = 43;
 
         public final static int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
-        /** @hide -- TODO(fadden): make this public before release */
-        public final static int COLOR_FormatAndroidOpaque             = 0x7F000789;
+        // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference.
+        // In OMX this is called OMX_COLOR_FormatAndroidOpaque.
+        public final static int COLOR_FormatSurface                   = 0x7F000789;
         public final static int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
 
         /**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
new file mode 100644
index 0000000..4eb0c56
--- /dev/null
+++ b/media/java/android/media/MediaDrm.java
@@ -0,0 +1,500 @@
+/*
+ * 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.media;
+
+import android.media.MediaDrmException;
+import java.lang.ref.WeakReference;
+import java.util.UUID;
+import java.util.HashMap;
+import java.util.List;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Bundle;
+import android.os.Parcel;
+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.
+ *
+ * <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.
+ * 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
+ * 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 {
+
+    private final static String TAG = "MediaDrm";
+
+    private EventHandler mEventHandler;
+    private OnEventListener mOnEventListener;
+
+    private int mNativeContext;
+
+    /**
+     * Query if the given scheme identified by its UUID is supported on
+     * this device.
+     * @param uuid The UUID of the crypto scheme.
+     */
+    public static final boolean isCryptoSchemeSupported(UUID uuid) {
+        return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid));
+    }
+
+    private static final byte[] getByteArrayFromUUID(UUID uuid) {
+        long msb = uuid.getMostSignificantBits();
+        long lsb = uuid.getLeastSignificantBits();
+
+        byte[] uuidBytes = new byte[16];
+        for (int i = 0; i < 8; ++i) {
+            uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
+            uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
+        }
+
+        return uuidBytes;
+    }
+
+    private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid);
+
+    /**
+     * Instantiate a MediaDrm object using opaque, crypto scheme specific
+     * data.
+     * @param uuid The UUID of the crypto scheme.
+     */
+    public MediaDrm(UUID uuid) throws MediaDrmException {
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else {
+            mEventHandler = null;
+        }
+
+        /* Native setup requires a weak reference to our object.
+         * It's easier to create it here than in C++.
+         */
+        native_setup(new WeakReference<MediaDrm>(this),
+                     getByteArrayFromUUID(uuid));
+    }
+
+    /**
+     * Register a callback to be invoked when an event occurs
+     *
+     * @param listener the callback that will be run
+     */
+    public void setOnEventListener(OnEventListener listener)
+    {
+        mOnEventListener = listener;
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when a drm event
+     * occurs.
+     */
+    public interface OnEventListener
+    {
+        /**
+         * Called when an event occurs that requires the app to be notified
+         *
+         * @param md the MediaDrm object on which the event occurred
+         * @param sessionId the DRM session ID on which the event occurred
+         * @param event indicates the event type
+         * @param extra an secondary error code
+         * @param data optional byte array of data that may be associated with the event
+         */
+        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;
+
+    private static final int DRM_EVENT = 200;
+
+    private class EventHandler extends Handler
+    {
+        private MediaDrm mMediaDrm;
+
+        public EventHandler(MediaDrm md, Looper looper) {
+            super(looper);
+            mMediaDrm = md;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (mMediaDrm.mNativeContext == 0) {
+                Log.w(TAG, "MediaDrm went away with unhandled events");
+                return;
+            }
+            switch(msg.what) {
+
+            case DRM_EVENT:
+                Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
+
+                if (mOnEventListener != null) {
+                    if (msg.obj != null && msg.obj instanceof Parcel) {
+                        Parcel parcel = (Parcel)msg.obj;
+                        byte[] sessionId = parcel.createByteArray();
+                        if (sessionId.length == 0) {
+                            sessionId = null;
+                        }
+                        byte[] data = parcel.createByteArray();
+                        if (data.length == 0) {
+                            data = null;
+                        }
+                        mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+                    }
+                }
+                return;
+
+            default:
+                Log.e(TAG, "Unknown message type " + msg.what);
+                return;
+            }
+        }
+    }
+
+    /*
+     * Called from native code when an interesting event happens.  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
+     * the cookie passed to native_setup().)
+     */
+    private static void postEventFromNative(Object mediadrm_ref,
+                                            int eventType, int extra, Object obj)
+    {
+        MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
+        if (md == null) {
+            return;
+        }
+        if (md.mEventHandler != null) {
+            Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
+            md.mEventHandler.sendMessage(m);
+        }
+    }
+
+    /**
+     *  Open a new session with the MediaDrm object.  A session ID is returned.
+     */
+    public native byte[] openSession() throws MediaDrmException;
+
+    /**
+     *  Close a session on the MediaDrm object that was previously opened
+     *  with {@link #openSession}.
+     */
+    public native void closeSession(byte[] sessionId) throws MediaDrmException;
+
+    public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
+    public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
+
+    public final class KeyRequest {
+        public KeyRequest() {}
+        public byte[] data;
+        public String defaultUrl;
+    };
+
+    /**
+     * 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
+     * returned in KeyRequest.defaultUrl.
+     *
+     * 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 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.
+     * @param mimeType identifies the mime type of the content
+     * @param keyType specifes if the request is for streaming or offline content
+     * @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,
+                                           String mimeType, int keyType,
+                                           HashMap<String, String> optionalParameters)
+        throws MediaDrmException;
+
+    /**
+     * 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.
+     *
+     * @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;
+
+    /**
+     * Restore persisted offline keys into a new session.  keySetId identifies the
+     * 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;
+
+    /**
+     * 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.
+     *
+     * @param keySetId identifies the saved key set to remove
+     */
+    public native void removeKeys(byte[] keySetId) throws MediaDrmException;
+
+    /**
+     * Request an informative description of the key status for the session.  The status is
+     * in the form of {name, value} pairs.  Since DRM license policies vary by vendor,
+     * the specific status field names are determined by each DRM vendor.  Refer to your
+     * DRM provider documentation for definitions of the field names for a particular
+     * DRM engine plugin.
+     *
+     * @param sessionId the session ID for the DRM session
+     */
+    public native HashMap<String, String> queryKeyStatus(byte[] sessionId)
+        throws MediaDrmException;
+
+    public final class ProvisionRequest {
+        public ProvisionRequest() {}
+        public byte[] data;
+        public String defaultUrl;
+    }
+
+    /**
+     * 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.
+     * 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;
+
+    /**
+     * After a provision response is received by the app, it is provided to the DRM
+     * engine plugin using this method.
+     *
+     * @param response the opaque provisioning response byte array to provide to the
+     * DRM engine plugin.
+     */
+    public native void provideProvisionResponse(byte[] response)
+        throws MediaDrmException;
+
+    /**
+     * 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.
+     *
+     * 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 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;
+
+
+    /**
+     * Process the SecureStop server response message ssRelease.  After authenticating
+     * the message, remove the SecureStops identiied in the response.
+     *
+     * @param ssRelease the server response indicating which secure stops to release
+     */
+    public native void releaseSecureStops(byte[] ssRelease)
+        throws MediaDrmException;
+
+
+    /**
+     * 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.
+     *
+     * 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.
+     */
+    public native String getPropertyString(String propertyName)
+        throws MediaDrmException;
+
+    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.
+     */
+    public native void setPropertyString(String propertyName, String value)
+        throws MediaDrmException;
+
+    public native void setPropertyByteArray(String propertyName, byte[] value)
+        throws MediaDrmException;
+
+    /**
+     * 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.
+     */
+
+    private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
+                                                              String algorithm);
+
+    private static final native void setMacAlgorithmNative(MediaDrm drm, byte[] sessionId,
+                                                           String algorithm);
+
+    private static final native byte[] encryptNative(MediaDrm drm, byte[] sessionId,
+                                                     byte[] keyId, byte[] input, byte[] iv);
+
+    private static final native byte[] decryptNative(MediaDrm drm, byte[] sessionId,
+                                                     byte[] keyId, byte[] input, byte[] iv);
+
+    private static final native byte[] signNative(MediaDrm drm, byte[] sessionId,
+                                                  byte[] keyId, byte[] message);
+
+    private static final native boolean verifyNative(MediaDrm drm, byte[] sessionId,
+                                                     byte[] keyId, byte[] message,
+                                                     byte[] signature);
+
+    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 {
+            mSessionId = sessionId;
+            mDrm = drm;
+            setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
+            setMacAlgorithmNative(drm, sessionId, macAlgorithm);
+        }
+
+        public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
+            return encryptNative(mDrm, mSessionId, keyid, input, iv);
+        }
+
+        public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
+            return decryptNative(mDrm, mSessionId, keyid, input, iv);
+        }
+
+        public byte[] sign(byte[] keyid, byte[] message) {
+            return signNative(mDrm, mSessionId, keyid, message);
+        }
+        public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
+            return verifyNative(mDrm, mSessionId, keyid, message, signature);
+        }
+    };
+
+    public CryptoSession getCryptoSession(byte[] sessionId,
+                                          String cipherAlgorithm,
+                                          String macAlgorithm)
+        throws MediaDrmException {
+        return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
+    }
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    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_finalize();
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+}
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
new file mode 100644
index 0000000..6f81f90
--- /dev/null
+++ b/media/java/android/media/MediaDrmException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.media;
+
+/**
+ * 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) {
+        super(detailMessage);
+    }
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 749ef12..286e203 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -26,7 +26,10 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.UUID;
 
 /**
  * MediaExtractor facilitates extraction of demuxed, typically encoded,  media data
@@ -195,6 +198,38 @@
     public native final int getTrackCount();
 
     /**
+     * Get the PSSH info if present. This returns a map of uuid-to-bytes, with the uuid specifying
+     * the crypto scheme, and the bytes being the data specific to that scheme.
+     * {@hide}
+     */
+    public Map<UUID, byte[]> getPsshInfo() {
+        Map<UUID, byte[]> psshMap = null;
+        Map<String, Object> formatMap = getFileFormatNative();
+        if (formatMap != null && formatMap.containsKey("pssh")) {
+            ByteBuffer rawpssh = (ByteBuffer) formatMap.get("pssh");
+            rawpssh.order(ByteOrder.nativeOrder());
+            rawpssh.rewind();
+            formatMap.remove("pssh");
+            // parse the flat pssh bytebuffer into something more manageable
+            psshMap = new HashMap<UUID, byte[]>();
+            while (rawpssh.remaining() > 0) {
+                rawpssh.order(ByteOrder.BIG_ENDIAN);
+                long msb = rawpssh.getLong();
+                long lsb = rawpssh.getLong();
+                UUID uuid = new UUID(msb, lsb);
+                rawpssh.order(ByteOrder.nativeOrder());
+                int datalen = rawpssh.getInt();
+                byte [] psshdata = new byte[datalen];
+                rawpssh.get(psshdata);
+                psshMap.put(uuid, psshdata);
+            }
+        }
+        return psshMap;
+    }
+
+    private native Map<String, Object> getFileFormatNative();
+
+    /**
      * Get the track format at the specified index.
      * More detail on the representation can be found at {@link android.media.MediaCodec}
      */
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index cc59d02..376bb2d 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -367,7 +367,7 @@
      * counterparts in include/media/mediametadataretriever.h!
      */
     /**
-     * The metadata key to retrieve the numberic string describing the
+     * The metadata key to retrieve the numeric string describing the
      * order of the audio data source on its original recording.
      */
     public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
new file mode 100644
index 0000000..c0fbd2e
--- /dev/null
+++ b/media/java/android/media/MediaMuxer.java
@@ -0,0 +1,317 @@
+/*
+ * 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.media;
+
+import android.media.MediaCodec.BufferInfo;
+
+import dalvik.system.CloseGuard;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+/**
+ * MediaMuxer facilitates muxing elementary streams. Currently only supports an
+ * mp4 file as the output and at most one audio and/or one video elementary
+ * stream.
+ * <p>
+ * It is generally used like this:
+ *
+ * <pre>
+ * MediaMuxer muxer = new MediaMuxer(...);
+ * MediaFormat audioFormat = new MediaFormat(...);
+ * MediaFormat videoFormat = new MediaFormat(...);
+ * int audioTrackIndex = muxer.addTrack(audioFormat);
+ * int videoTrackIndex = muxer.addTrack(videoFormat);
+ * ByteBuffer inputBuffer = ByteBuffer.allocate(...);
+ * muxer.start();
+ * while(inputBuffer has new data) {
+ *   if (new data is audio sample) {
+ *     muxer.writeSampleData(audioTrackIndex, inputBuffer, ...);
+ *   } else if (new data is video sample) {
+ *     muxer.writeSampleData(videoTrackIndex, inputBuffer, ...);
+ *   }
+ * }
+ * muxer.stop();
+ * muxer.release();
+ * </pre>
+ */
+
+final public class MediaMuxer {
+
+    private int mNativeContext;
+
+    static {
+        System.loadLibrary("media_jni");
+    }
+
+    /**
+     * Defines the output format. These constants are used with constructor.
+     */
+    public static final class OutputFormat {
+        /* Do not change these values without updating their counterparts
+         * in include/media/stagefright/MediaMuxer.h!
+         */
+        private OutputFormat() {}
+        /** MPEG4 media file format*/
+        public static final int MUXER_OUTPUT_MPEG_4 = 0;
+    };
+
+    /**
+     * The sample is a sync sample, which does not require other video samples
+     * to decode. This flag is used in {@link #writeSampleData} to indicate
+     * which sample is a sync sample.
+     */
+    /* Keep this flag in sync with its equivalent in
+     * include/media/stagefright/MediaMuxer.h.
+     */
+    public static final int SAMPLE_FLAG_SYNC = 1;
+
+    // All the native functions are listed here.
+    private static native int nativeSetup(FileDescriptor fd, int format);
+    private static native void nativeRelease(int nativeObject);
+    private static native void nativeStart(int nativeObject);
+    private static native void nativeStop(int nativeObject);
+    private static native int nativeAddTrack(int nativeObject, String[] keys,
+            Object[] values);
+    private static native void nativeSetOrientationHint(int nativeObject,
+            int degrees);
+    private static native void nativeWriteSampleData(int nativeObject,
+            int trackIndex, ByteBuffer byteBuf,
+            int offset, int size, long presentationTimeUs, int flags);
+
+    // Muxer internal states.
+    private static final int MUXER_STATE_UNINITIALIZED  = -1;
+    private static final int MUXER_STATE_INITIALIZED    = 0;
+    private static final int MUXER_STATE_STARTED        = 1;
+    private static final int MUXER_STATE_STOPPED        = 2;
+
+    private int mState = MUXER_STATE_UNINITIALIZED;
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private int mLastTrackIndex = -1;
+
+    private int mNativeObject;
+
+    /**
+     * Constructor.
+     * Creates a media muxer that writes to the specified path.
+     * @param path The path of the output media file.
+     * @param format The format of the output media file.
+     * @see android.media.MediaMuxer.OutputFormat
+     * @throws IOException if failed to open the file for write
+     */
+    public MediaMuxer(String path, int format) throws IOException {
+        if (path == null) {
+            throw new IllegalArgumentException("path must not be null");
+        }
+        if (format != OutputFormat.MUXER_OUTPUT_MPEG_4) {
+            throw new IllegalArgumentException("format is invalid");
+        }
+        FileOutputStream fos = null;
+        try {
+            File file = new File(path);
+            fos = new FileOutputStream(file);
+            FileDescriptor fd = fos.getFD();
+            mNativeObject = nativeSetup(fd, format);
+            mState = MUXER_STATE_INITIALIZED;
+            mCloseGuard.open("release");
+        } finally {
+            if (fos != null) {
+                fos.close();
+            }
+        }
+    }
+
+    /**
+     * Sets the orientation hint for output video playback.
+     * <p>This method should be called before {@link #start}. Calling this
+     * method will not rotate the video frame when muxer is generating the file,
+     * but add a composition matrix containing the rotation angle in the output
+     * video if the output format is
+     * {@link OutputFormat#MUXER_OUTPUT_MPEG_4} so that a video player can
+     * choose the proper orientation for playback. Note that some video players
+     * may choose to ignore the composition matrix in a video during playback.
+     * By default, the rotation degree is 0.</p>
+     * @param degrees the angle to be rotated clockwise in degrees.
+     * The supported angles are 0, 90, 180, and 270 degrees.
+     */
+    public void setOrientationHint(int degrees) {
+        if (degrees != 0 && degrees != 90  && degrees != 180 && degrees != 270) {
+            throw new IllegalArgumentException("Unsupported angle: " + degrees);
+        }
+        if (mState == MUXER_STATE_INITIALIZED) {
+            nativeSetOrientationHint(mNativeObject, degrees);
+        } else {
+            throw new IllegalStateException("Can't set rotation degrees due" +
+                    " to wrong state.");
+        }
+    }
+
+    /**
+     * Starts the muxer.
+     * <p>Make sure this is called after {@link #addTrack} and before
+     * {@link #writeSampleData}.</p>
+     */
+    public void start() {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("Muxer has been released!");
+        }
+        if (mState == MUXER_STATE_INITIALIZED) {
+            nativeStart(mNativeObject);
+            mState = MUXER_STATE_STARTED;
+        } else {
+            throw new IllegalStateException("Can't start due to wrong state.");
+        }
+    }
+
+    /**
+     * Stops the muxer.
+     * <p>Once the muxer stops, it can not be restarted.</p>
+     */
+    public void stop() {
+        if (mState == MUXER_STATE_STARTED) {
+            nativeStop(mNativeObject);
+            mState = MUXER_STATE_STOPPED;
+        } else {
+            throw new IllegalStateException("Can't stop due to wrong state.");
+        }
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+            if (mNativeObject != 0) {
+                nativeRelease(mNativeObject);
+                mNativeObject = 0;
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Adds a track with the specified format.
+     * @param format The media format for the track.
+     * @return The track index for this newly added track, and it should be used
+     * in the {@link #writeSampleData}.
+     */
+    public int addTrack(MediaFormat format) {
+        if (format == null) {
+            throw new IllegalArgumentException("format must not be null.");
+        }
+        if (mState != MUXER_STATE_INITIALIZED) {
+            throw new IllegalStateException("Muxer is not initialized.");
+        }
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("Muxer has been released!");
+        }
+        int trackIndex = -1;
+        // Convert the MediaFormat into key-value pairs and send to the native.
+        Map<String, Object> formatMap = format.getMap();
+
+        String[] keys = null;
+        Object[] values = null;
+        int mapSize = formatMap.size();
+        if (mapSize > 0) {
+            keys = new String[mapSize];
+            values = new Object[mapSize];
+            int i = 0;
+            for (Map.Entry<String, Object> entry : formatMap.entrySet()) {
+                keys[i] = entry.getKey();
+                values[i] = entry.getValue();
+                ++i;
+            }
+            trackIndex = nativeAddTrack(mNativeObject, keys, values);
+        } else {
+            throw new IllegalArgumentException("format must not be empty.");
+        }
+
+        // Track index number is expected to incremented as addTrack succeed.
+        // However, if format is invalid, it will get a negative trackIndex.
+        if (mLastTrackIndex >= trackIndex) {
+            throw new IllegalArgumentException("Invalid format.");
+        }
+        mLastTrackIndex = trackIndex;
+        return trackIndex;
+    }
+
+    /**
+     * Writes an encoded sample into the muxer.
+     * <p>The application needs to make sure that the samples are written into
+     * the right tracks. Also, it needs to make sure the samples for each track
+     * are written in chronological order.</p>
+     * @param byteBuf The encoded sample.
+     * @param trackIndex The track index for this sample.
+     * @param bufferInfo The buffer information related to this sample.
+     */
+    public void writeSampleData(int trackIndex, ByteBuffer byteBuf,
+            BufferInfo bufferInfo) {
+        if (trackIndex < 0 || trackIndex > mLastTrackIndex) {
+            throw new IllegalArgumentException("trackIndex is invalid");
+        }
+
+        if (byteBuf == null) {
+            throw new IllegalArgumentException("byteBuffer must not be null");
+        }
+
+        if (bufferInfo == null) {
+            throw new IllegalArgumentException("bufferInfo must not be null");
+        }
+        if (bufferInfo.size < 0 || bufferInfo.offset < 0
+                || (bufferInfo.offset + bufferInfo.size) > byteBuf.capacity()
+                || bufferInfo.presentationTimeUs < 0) {
+            throw new IllegalArgumentException("bufferInfo must specify a" +
+                    " valid buffer offset, size and presentation time");
+        }
+
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("Muxer has been released!");
+        }
+
+        if (mState != MUXER_STATE_STARTED) {
+            throw new IllegalStateException("Can't write, muxer is not started");
+        }
+
+        nativeWriteSampleData(mNativeObject, trackIndex, byteBuf,
+                bufferInfo.offset, bufferInfo.size,
+                bufferInfo.presentationTimeUs, bufferInfo.flags);
+    }
+
+    /**
+     * Make sure you call this when you're done to free up any resources
+     * instead of relying on the garbage collector to do this for you at
+     * some point in the future.
+     */
+    public void release() {
+        if (mState == MUXER_STATE_STARTED) {
+            stop();
+        }
+        if (mNativeObject != 0) {
+            nativeRelease(mNativeObject);
+            mNativeObject = 0;
+            mCloseGuard.close();
+        }
+        mState = MUXER_STATE_UNINITIALIZED;
+    }
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 11f4180..85a32ca 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -328,8 +328,8 @@
  *         the state. Calling this method in an invalid state transfers the
  *         object to the <em>Error</em> state. </p></td></tr>
  * <tr><td>pause </p></td>
- *     <td>{Started, Paused}</p></td>
- *     <td>{Idle, Initialized, Prepared, Stopped, PlaybackCompleted, Error}</p></td>
+ *     <td>{Started, Paused, PlaybackCompleted}</p></td>
+ *     <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
  *     <td>Successful invoke of this method in a valid state transfers the
  *         object to the <em>Paused</em> state. Calling this method in an
  *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 8b489b1..795c3c2 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -299,16 +299,21 @@
     }
 
     /**
-     * @hide for use by framework routing UI
+     * Gets the default route for playing media content on the system.
+     * <p>
+     * The system always provides a default route.
+     * </p>
+     *
+     * @return The default route, which is guaranteed to never be null.
      */
-    public RouteInfo getSystemAudioRoute() {
+    public RouteInfo getDefaultRoute() {
         return sStatic.mDefaultAudioVideo;
     }
 
     /**
      * @hide for use by framework routing UI
      */
-    public RouteCategory getSystemAudioCategory() {
+    public RouteCategory getSystemCategory() {
         return sStatic.mSystemCategory;
     }
 
@@ -372,14 +377,17 @@
 
     /**
      * Select the specified route to use for output of the given media types.
+     * <p class="note">
+     * As API version 18, this function may be used to select any route.
+     * In prior versions, this function could only be used to select user
+     * routes and would ignore any attempt to select a system route.
+     * </p>
      *
      * @param types type flags indicating which types this route should be used for.
      *              The route must support at least a subset.
      * @param route Route to select
      */
     public void selectRoute(int types, RouteInfo route) {
-        // Applications shouldn't programmatically change anything but user routes.
-        types &= ROUTE_TYPE_USER;
         selectRouteStatic(types, route);
     }
     
@@ -454,7 +462,7 @@
      * App-specified route definitions are created using {@link #createUserRoute(RouteCategory)}
      *
      * @param info Definition of the route to add
-     * @see #createUserRoute()
+     * @see #createUserRoute(RouteCategory)
      * @see #removeUserRoute(UserRouteInfo)
      */
     public void addUserRoute(UserRouteInfo info) {
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 4c71ace..93bcf03 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -36,6 +36,8 @@
 import android.util.Log;
 
 import java.lang.IllegalArgumentException;
+import java.util.ArrayList;
+import java.util.Iterator;
 
 /**
  * RemoteControlClient enables exposing information meant to be consumed by remote controls
@@ -170,6 +172,17 @@
      */
     public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE;
 
+    /**
+     * @hide
+     * An unknown or invalid playback position value.
+     */
+    public final static long PLAYBACK_POSITION_INVALID = -1;
+    /**
+     * @hide
+     * The default playback speed, 1x.
+     */
+    public final static float PLAYBACK_SPEED_1X = 1.0f;
+
     //==========================================
     // Public keys for playback information
     /**
@@ -206,15 +219,7 @@
     public final static int PLAYBACKINFO_USES_STREAM = 5;
 
     //==========================================
-    // Private keys for playback information
-    /**
-     * @hide
-     * Used internally to relay playback state (set by the application with
-     * {@link #setPlaybackState(int)}) to AudioService
-     */
-    public final static int PLAYBACKINFO_PLAYSTATE = 255;
-
-
+    // Public flags for the supported transport control capabililities
     /**
      * Flag indicating a RemoteControlClient makes use of the "previous" media key.
      *
@@ -271,6 +276,18 @@
      * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
      */
     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
+     * 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 #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
+     */
+    public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
 
     /**
      * @hide
@@ -498,13 +515,7 @@
             if (key != BITMAP_KEY_ARTWORK) {
                 throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
             }
-            if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
-                mEditorArtwork = scaleBitmapIfTooBig(bitmap,
-                        mArtworkExpectedWidth, mArtworkExpectedHeight);
-            } else {
-                // no valid resize dimensions, store as is
-                mEditorArtwork = bitmap;
-            }
+            mEditorArtwork = bitmap;
             mArtworkChanged = true;
             return this;
         }
@@ -536,10 +547,10 @@
             synchronized(mCacheLock) {
                 // assign the edited data
                 mMetadata = new Bundle(mEditorMetadata);
-                if ((mArtwork != null) && (!mArtwork.equals(mEditorArtwork))) {
-                    mArtwork.recycle();
+                if ((mOriginalArtwork != null) && (!mOriginalArtwork.equals(mEditorArtwork))) {
+                    mOriginalArtwork.recycle();
                 }
-                mArtwork = mEditorArtwork;
+                mOriginalArtwork = mEditorArtwork;
                 mEditorArtwork = null;
                 if (mMetadataChanged & mArtworkChanged) {
                     // send to remote control display if conditions are met
@@ -571,7 +582,7 @@
             editor.mArtworkChanged = true;
         } else {
             editor.mEditorMetadata = new Bundle(mMetadata);
-            editor.mEditorArtwork = mArtwork;
+            editor.mEditorArtwork = mOriginalArtwork;
             editor.mMetadataChanged = false;
             editor.mArtworkChanged = false;
         }
@@ -592,17 +603,49 @@
      *       {@link #PLAYSTATE_ERROR}.
      */
     public void setPlaybackState(int state) {
+        setPlaybackState(state, PLAYBACK_POSITION_INVALID, PLAYBACK_SPEED_1X);
+    }
+
+    /**
+     * @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:
+     *       {@link #PLAYSTATE_STOPPED},
+     *       {@link #PLAYSTATE_PAUSED},
+     *       {@link #PLAYSTATE_PLAYING},
+     *       {@link #PLAYSTATE_FAST_FORWARDING},
+     *       {@link #PLAYSTATE_REWINDING},
+     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
+     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
+     *       {@link #PLAYSTATE_BUFFERING},
+     *       {@link #PLAYSTATE_ERROR}.
+     * @param timeInMs a 0 or positive value for the current media position expressed in ms
+     *    (same unit as for when sending the media duration, if applicable, with
+     *    {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} in the
+     *    {@link RemoteControlClient.MetadataEditor}). Negative values imply that position is not
+     *    known (e.g. listening to a live stream of a radio) or not applicable (e.g. when state
+     *    is {@link #PLAYSTATE_BUFFERING} and nothing had played yet).
+     * @param playbackSpeed a value expressed as a ratio of 1x playback: 1.0f is normal playback,
+     *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
+     *    playing (e.g. when state is {@link #PLAYSTATE_ERROR}).
+     */
+    public void setPlaybackState(int state, long timeInMs, float playbackSpeed) {
         synchronized(mCacheLock) {
-            if (mPlaybackState != state) {
+            if ((mPlaybackState != state) || (mPlaybackPositionMs != timeInMs)
+                    || (mPlaybackSpeed != playbackSpeed)) {
                 // store locally
                 mPlaybackState = state;
+                mPlaybackPositionMs = timeInMs;
+                mPlaybackSpeed = playbackSpeed;
                 // keep track of when the state change occurred
                 mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
 
                 // send to remote control display if conditions are met
                 sendPlaybackState_syncCacheLock();
                 // update AudioService
-                sendAudioServiceNewPlaybackInfo_syncCacheLock(PLAYBACKINFO_PLAYSTATE, state);
+                sendAudioServiceNewPlaybackState_syncCacheLock();
             }
         }
     }
@@ -625,10 +668,115 @@
             mTransportControlFlags = transportControlFlags;
 
             // send to remote control display if conditions are met
-            sendTransportControlFlags_syncCacheLock();
+            sendTransportControlInfo_syncCacheLock();
         }
     }
 
+    /**
+     * @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
+     */
+    public interface OnPlaybackPositionUpdateListener {
+        /**
+         * 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
+         * 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
+         * the position was updated.
+         * @param newPositionMs the new requested position in the current media, expressed in ms.
+         */
+        void onPlaybackPositionUpdate(long newPositionMs);
+    }
+
+    /**
+     * @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 {
+        /**
+         * 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();
+    }
+
+    /**
+     * @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
+     */
+    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
+        synchronized(mCacheLock) {
+            int oldCapa = mPlaybackPositionCapabilities;
+            if (l != null) {
+                mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
+            } else {
+                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
+            }
+            mPositionUpdateListener = l;
+            if (oldCapa != mPlaybackPositionCapabilities) {
+                // tell RCDs that this RCC's playback position capabilities have changed
+                sendTransportControlInfo_syncCacheLock();
+            }
+        }
+    }
+
+    /**
+     * @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
+     */
+    public void setPlaybackPositionProvider(PlaybackPositionProvider l) {
+        synchronized(mCacheLock) {
+            int oldCapa = mPlaybackPositionCapabilities;
+            if (l != null) {
+                mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
+            } else {
+                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
+            }
+            mPositionProvider = l;
+            if (oldCapa != mPlaybackPositionCapabilities) {
+                // tell RCDs that this RCC's playback position capabilities have changed
+                sendTransportControlInfo_syncCacheLock();
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Flag to reflect that the application controlling this RemoteControlClient sends playback
+     * position updates. The playback position being "readable" is considered from the application's
+     * point of view.
+     */
+    public static int MEDIA_POSITION_READABLE = 1 << 0;
+    /**
+     * @hide
+     * Flag to reflect that the application controlling this RemoteControlClient can receive
+     * playback position updates. The playback position being "writable"
+     * is considered from the application's point of view.
+     */
+    public static int MEDIA_POSITION_WRITABLE = 1 << 1;
+
+    private int mPlaybackPositionCapabilities = 0;
+
     /** @hide */
     public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
     /** @hide */
@@ -760,17 +908,21 @@
      */
     private long mPlaybackStateChangeTimeMs = 0;
     /**
+     * Last playback position in ms reported by the user
+     */
+    private long mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
+    /**
+     * Last playback speed reported by the user
+     */
+    private float mPlaybackSpeed = PLAYBACK_SPEED_1X;
+    /**
      * Cache for the artwork bitmap.
      * Access synchronized on mCacheLock
      * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be
      * accessed to be resized, in which case a copy will be made. This would add overhead in
      * Bundle operations.
      */
-    private Bitmap mArtwork;
-    private final int ARTWORK_DEFAULT_SIZE = 256;
-    private final int ARTWORK_INVALID_SIZE = -1;
-    private int mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
-    private int mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
+    private Bitmap mOriginalArtwork;
     /**
      * Cache for the transport control mask.
      * Access synchronized on mCacheLock
@@ -782,9 +934,17 @@
      * This is re-initialized in apply() and so cannot be final.
      */
     private Bundle mMetadata = new Bundle();
-
     /**
-     * The current remote control client generation ID across the system
+     * Listener registered by user of RemoteControlClient to receive requests for playback position
+     * update requests.
+     */
+    private OnPlaybackPositionUpdateListener mPositionUpdateListener;
+    /**
+     * Provider registered by user of RemoteControlClient to provide the current playback position.
+     */
+    private PlaybackPositionProvider mPositionProvider;
+    /**
+     * The current remote control client generation ID across the system, as known by this object
      */
     private int mCurrentClientGenId = -1;
     /**
@@ -797,15 +957,33 @@
 
     /**
      * The media button intent description associated with this remote control client
-     * (can / should include target component for intent handling)
+     * (can / should include target component for intent handling, used when persisting media
+     *    button event receiver across reboots).
      */
     private final PendingIntent mRcMediaIntent;
 
     /**
-     * The remote control display to which this client will send information.
-     * NOTE: Only one IRemoteControlDisplay supported in this implementation
+     * A class to encapsulate all the information about a remote control display.
+     * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
      */
-    private IRemoteControlDisplay mRcDisplay;
+    private class DisplayInfoForClient {
+        /** may never be null */
+        private IRemoteControlDisplay mRcDisplay;
+        private int mArtworkExpectedWidth;
+        private int mArtworkExpectedHeight;
+
+        DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) {
+            mRcDisplay = rcd;
+            mArtworkExpectedWidth = w;
+            mArtworkExpectedHeight = h;
+        }
+    }
+
+    /**
+     * The list of remote control displays to which this client will send information.
+     * Accessed and modified synchronized on mCacheLock
+     */
+    private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1);
 
     /**
      * @hide
@@ -827,17 +1005,14 @@
      */
     private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
 
-        public void onInformationRequested(int clientGeneration, int infoFlags,
-                int artWidth, int artHeight) {
+        public void onInformationRequested(int generationId, int infoFlags) {
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 // signal new client
                 mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
                 mEventHandler.dispatchMessage(
-                        mEventHandler.obtainMessage(
-                                MSG_NEW_INTERNAL_CLIENT_GEN,
-                                artWidth, artHeight,
-                                new Integer(clientGeneration)));
+                        mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
+                                /*arg1*/ generationId, /*arg2, ignored*/ 0));
                 // send the information
                 mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
                 mEventHandler.removeMessages(MSG_REQUEST_METADATA);
@@ -861,21 +1036,39 @@
             }
         }
 
-        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd) {
+        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
             // only post messages, we can't block here
-            if (mEventHandler != null) {
+            if ((mEventHandler != null) && (rcd != null)) {
                 mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
-                        MSG_PLUG_DISPLAY, rcd));
+                        MSG_PLUG_DISPLAY, w, h, rcd));
             }
         }
 
         public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
             // only post messages, we can't block here
-            if (mEventHandler != null) {
+            if ((mEventHandler != null) && (rcd != null)) {
                 mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
                         MSG_UNPLUG_DISPLAY, rcd));
             }
         }
+
+        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(
+                        MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
+            }
+        }
+
+        public void seekTo(int generationId, long timeMs) {
+            // only post messages, we can't block here
+            if (mEventHandler != null) {
+                mEventHandler.removeMessages(MSG_SEEK_TO);
+                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                        MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
+                        new Long(timeMs)));
+            }
+        }
     };
 
     /**
@@ -915,6 +1108,8 @@
     private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
     private final static int MSG_PLUG_DISPLAY = 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 class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -936,7 +1131,7 @@
                     break;
                 case MSG_REQUEST_TRANSPORTCONTROL:
                     synchronized (mCacheLock) {
-                        sendTransportControlFlags_syncCacheLock();
+                        sendTransportControlInfo_syncCacheLock();
                     }
                     break;
                 case MSG_REQUEST_ARTWORK:
@@ -945,17 +1140,22 @@
                     }
                     break;
                 case MSG_NEW_INTERNAL_CLIENT_GEN:
-                    onNewInternalClientGen((Integer)msg.obj, msg.arg1, msg.arg2);
+                    onNewInternalClientGen(msg.arg1);
                     break;
                 case MSG_NEW_CURRENT_CLIENT_GEN:
                     onNewCurrentClientGen(msg.arg1);
                     break;
                 case MSG_PLUG_DISPLAY:
-                    onPlugDisplay((IRemoteControlDisplay)msg.obj);
+                    onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
                     break;
                 case MSG_UNPLUG_DISPLAY:
                     onUnplugDisplay((IRemoteControlDisplay)msg.obj);
                     break;
+                case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
+                    onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
+                    break;
+                case MSG_SEEK_TO:
+                    onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
             }
@@ -963,75 +1163,107 @@
     }
 
     //===========================================================
-    // Communication with IRemoteControlDisplay
-
-    private void detachFromDisplay_syncCacheLock() {
-        mRcDisplay = null;
-        mArtworkExpectedWidth = ARTWORK_INVALID_SIZE;
-        mArtworkExpectedHeight = ARTWORK_INVALID_SIZE;
-    }
+    // Communication with the IRemoteControlDisplay (the displays known to the system)
 
     private void sendPlaybackState_syncCacheLock() {
-        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
-            try {
-                mRcDisplay.setPlaybackState(mInternalClientGenId, mPlaybackState,
-                        mPlaybackStateChangeTimeMs);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error in setPlaybackState(), dead display "+e);
-                detachFromDisplay_syncCacheLock();
+        if (mCurrentClientGenId == mInternalClientGenId) {
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                try {
+                    di.mRcDisplay.setPlaybackState(mInternalClientGenId,
+                            mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
+                            mPlaybackSpeed);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
+                    displayIterator.remove();
+                }
             }
         }
     }
 
     private void sendMetadata_syncCacheLock() {
-        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
-            try {
-                mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error in sendPlaybackState(), dead display "+e);
-                detachFromDisplay_syncCacheLock();
+        if (mCurrentClientGenId == mInternalClientGenId) {
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                try {
+                    di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e);
+                    displayIterator.remove();
+                }
             }
         }
     }
 
-    private void sendTransportControlFlags_syncCacheLock() {
-        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
-            try {
-                mRcDisplay.setTransportControlFlags(mInternalClientGenId,
-                        mTransportControlFlags);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error in sendTransportControlFlags(), dead display "+e);
-                detachFromDisplay_syncCacheLock();
+    private void sendTransportControlInfo_syncCacheLock() {
+        if (mCurrentClientGenId == mInternalClientGenId) {
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                try {
+                    di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
+                            mTransportControlFlags, mPlaybackPositionCapabilities);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
+                            e);
+                    displayIterator.remove();
+                }
             }
         }
     }
 
     private void sendArtwork_syncCacheLock() {
-        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
-            // even though we have already scaled in setArtwork(), when this client needs to
-            // send the bitmap, there might be newer and smaller expected dimensions, so we have
-            // to check again.
-            mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
-            try {
-                mRcDisplay.setArtwork(mInternalClientGenId, mArtwork);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error in sendArtwork(), dead display "+e);
-                detachFromDisplay_syncCacheLock();
+        // FIXME modify to cache all requested sizes?
+        if (mCurrentClientGenId == mInternalClientGenId) {
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
+                    displayIterator.remove();
+                }
             }
         }
     }
 
-    private void sendMetadataWithArtwork_syncCacheLock() {
-        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
-            // even though we have already scaled in setArtwork(), when this client needs to
-            // send the bitmap, there might be newer and smaller expected dimensions, so we have
-            // to check again.
-            mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
+    /**
+     * Send artwork to an IRemoteControlDisplay.
+     * @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its
+     *    dimension requirements.
+     * @return false if there was an error communicating with the IRemoteControlDisplay.
+     */
+    private boolean sendArtworkToDisplay(DisplayInfoForClient di) {
+        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
+            Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
+                    di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
             try {
-                mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, mArtwork);
+                di.mRcDisplay.setArtwork(mInternalClientGenId, artwork);
             } catch (RemoteException e) {
-                Log.e(TAG, "Error in setAllMetadata(), dead display "+e);
-                detachFromDisplay_syncCacheLock();
+                Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void sendMetadataWithArtwork_syncCacheLock() {
+        // FIXME modify to cache all requested sizes?
+        if (mCurrentClientGenId == mInternalClientGenId) {
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                try {
+                    if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
+                        Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
+                                di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
+                        di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
+                    } else {
+                        di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e);
+                    displayIterator.remove();
+                }
             }
         }
     }
@@ -1060,22 +1292,31 @@
         try {
             service.setPlaybackInfoForRcc(mRcseId, what, value);
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in sendAudioServiceNewPlaybackInfo_syncCacheLock", e);
+            Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e);
+        }
+    }
+
+    private void sendAudioServiceNewPlaybackState_syncCacheLock() {
+        if (mRcseId == RCSE_ID_UNREGISTERED) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            service.setPlaybackStateForRcc(mRcseId,
+                    mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setPlaybackStateForRcc", e);
         }
     }
 
     //===========================================================
     // Message handlers
 
-    private void onNewInternalClientGen(Integer clientGeneration, int artWidth, int artHeight) {
+    private void onNewInternalClientGen(int clientGeneration) {
         synchronized (mCacheLock) {
             // this remote control client is told it is the "focused" one:
             // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
-            mInternalClientGenId = clientGeneration.intValue();
-            if (artWidth > 0) {
-                mArtworkExpectedWidth = artWidth;
-                mArtworkExpectedHeight = artHeight;
-            }
+            mInternalClientGenId = clientGeneration;
         }
     }
 
@@ -1085,18 +1326,70 @@
         }
     }
 
-    private void onPlugDisplay(IRemoteControlDisplay rcd) {
+    /** pre-condition rcd != null */
+    private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) {
         synchronized(mCacheLock) {
-            mRcDisplay = rcd;
+            // do we have this display already?
+            boolean displayKnown = false;
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext() && !displayKnown) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
+                if (displayKnown) {
+                    // this display was known but the change in artwork size will cause the
+                    // artwork to be refreshed
+                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
+                        di.mArtworkExpectedWidth = w;
+                        di.mArtworkExpectedHeight = h;
+                        if (!sendArtworkToDisplay(di)) {
+                            displayIterator.remove();
+                        }
+                    }
+                }
+            }
+            if (!displayKnown) {
+                mRcDisplays.add(new DisplayInfoForClient(rcd, w, h));
+            }
         }
     }
 
+    /** pre-condition rcd != null */
     private void onUnplugDisplay(IRemoteControlDisplay rcd) {
         synchronized(mCacheLock) {
-            if ((mRcDisplay != null) && (mRcDisplay.asBinder().equals(rcd.asBinder()))) {
-                mRcDisplay = null;
-                mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
-                mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
+                    displayIterator.remove();
+                    return;
+                }
+            }
+        }
+    }
+
+    /** pre-condition rcd != null */
+    private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) {
+        synchronized(mCacheLock) {
+            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
+            while (displayIterator.hasNext()) {
+                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
+                if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
+                        ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
+                    di.mArtworkExpectedWidth = w;
+                    di.mArtworkExpectedHeight = h;
+                    if (!sendArtworkToDisplay(di)) {
+                        displayIterator.remove();
+                    }
+                    break;
+                }
+            }
+        }
+    }
+
+    private void onSeekTo(int generationId, long timeMs) {
+        synchronized (mCacheLock) {
+            if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
+                mPositionUpdateListener.onPlaybackPositionUpdate(timeMs);
             }
         }
     }
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 68a09de..031326e 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -72,55 +72,49 @@
      * specification. The definitions match the corresponding interface IDs in
      * OpenSLES_IID.h
      */
-
     /**
-     * UUID for environmental reverb effect
-     * @hide
+     * UUID for environmental reverberation effect
      */
     public static final UUID EFFECT_TYPE_ENV_REVERB = UUID
             .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
     /**
-     * UUID for preset reverb effect
-     * @hide
+     * UUID for preset reverberation effect
      */
     public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID
             .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
     /**
      * UUID for equalizer effect
-     * @hide
      */
     public static final UUID EFFECT_TYPE_EQUALIZER = UUID
             .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
     /**
      * UUID for bass boost effect
-     * @hide
      */
     public static final UUID EFFECT_TYPE_BASS_BOOST = UUID
             .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
     /**
      * UUID for virtualizer effect
-     * @hide
      */
     public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID
             .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
 
     /**
-     * UUID for Automatic Gain Control (AGC) audio pre-processing
-     * @hide
+     * UUIDs for effect types not covered by OpenSL ES.
+     */
+    /**
+     * UUID for Automatic Gain Control (AGC)
      */
     public static final UUID EFFECT_TYPE_AGC = UUID
             .fromString("0a8abfe0-654c-11e0-ba26-0002a5d5c51b");
 
     /**
-     * UUID for Acoustic Echo Canceler (AEC) audio pre-processing
-     * @hide
+     * UUID for Acoustic Echo Canceler (AEC)
      */
     public static final UUID EFFECT_TYPE_AEC = UUID
             .fromString("7b491460-8d4d-11e0-bd61-0002a5d5c51b");
 
     /**
-     * UUID for Noise Suppressor (NS) audio pre-processing
-     * @hide
+     * UUID for Noise Suppressor (NS)
      */
     public static final UUID EFFECT_TYPE_NS = UUID
             .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
@@ -199,7 +193,7 @@
      * The effect descriptor contains information on a particular effect implemented in the
      * audio framework:<br>
      * <ul>
-     *  <li>type: UUID corresponding to the OpenSL ES interface implemented by this effect</li>
+     *  <li>type: UUID identifying the effect type</li>
      *  <li>uuid: UUID for this particular implementation</li>
      *  <li>connectMode: {@link #EFFECT_INSERT}, {@link #EFFECT_AUXILIARY} or
      *  {at_link #EFFECT_PRE_PROCESSING}</li>
@@ -224,8 +218,14 @@
         }
 
         /**
-         *  Indicates the generic type of the effect (Equalizer, Bass boost ...). The UUID
-         *  corresponds to the OpenSL ES Interface ID for this type of effect.
+         *  Indicates the generic type of the effect (Equalizer, Bass boost ...).
+         *  One of {@link AudioEffect#EFFECT_TYPE_AEC},
+         *  {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST},
+         *  {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, {@link AudioEffect#EFFECT_TYPE_EQUALIZER},
+         *  {@link AudioEffect#EFFECT_TYPE_NS}, {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}
+         *   or {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}.<br>
+         *  For reverberation, bass boost, EQ and virtualizer, the UUID
+         *  corresponds to the OpenSL ES Interface ID.
          */
         public UUID type;
         /**
@@ -440,7 +440,7 @@
     }
 
     /**
-     * Query all audio pre processing effects applied to the AudioRecord with the supplied
+     * Query all audio pre-processing effects applied to the AudioRecord with the supplied
      * audio session ID. Returns an array of {@link android.media.audiofx.AudioEffect.Descriptor}
      * objects.
      * @param audioSession system wide unique audio session identifier.
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index ea12803..632334b 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -96,7 +96,8 @@
             Files.FileColumns.FORMAT, // 2
             Files.FileColumns.PARENT, // 3
             Files.FileColumns.DATA, // 4
-            Files.FileColumns.DATE_MODIFIED, // 5
+            Files.FileColumns.DATE_ADDED, // 5
+            Files.FileColumns.DATE_MODIFIED, // 6
     };
     private static final String ID_WHERE = Files.FileColumns._ID + "=?";
     private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
@@ -840,7 +841,7 @@
     }
 
     private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
-                        char[] outName, long[] outModified) {
+                        char[] outName, long[] outCreatedModified) {
         Cursor c = null;
         try {
             c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
@@ -861,7 +862,12 @@
                 path.getChars(start, end, outName, 0);
                 outName[end - start] = 0;
 
-                outModified[0] = c.getLong(5);
+                outCreatedModified[0] = c.getLong(5);
+                outCreatedModified[1] = c.getLong(6);
+                // use modification date as creation date if date added is not set
+                if (outCreatedModified[0] == 0) {
+                    outCreatedModified[0] = outCreatedModified[1];
+                }
                 return true;
             }
         } catch (RemoteException e) {
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 6aaab220..416a2a1 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -5,7 +5,9 @@
     android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
     android_media_MediaCodecList.cpp \
+    android_media_MediaDrm.cpp \
     android_media_MediaExtractor.cpp \
+    android_media_MediaMuxer.cpp \
     android_media_MediaPlayer.cpp \
     android_media_MediaRecorder.cpp \
     android_media_MediaScanner.cpp \
@@ -26,6 +28,7 @@
     libmedia \
     libskia \
     libui \
+    liblog \
     libcutils \
     libgui \
     libstagefright \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 3a42db2..cd1d9ce 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -372,7 +372,7 @@
 
         default:
         {
-            jniThrowException(env, "java/lang/IllegalStateException", NULL);
+            jniThrowException(env, "java/lang/IllegalStateException", msg);
             break;
         }
     }
@@ -455,13 +455,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        jniThrowException(env, "java/lang/IllegalStateException", "no codec found");
         return;
     }
 
     status_t err = codec->start();
 
-    throwExceptionAsNecessary(env, err);
+    throwExceptionAsNecessary(env, err, "start failed");
 }
 
 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index 517a293..d0f56ea 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -74,7 +74,7 @@
 
     sp<ICrypto> crypto = service->makeCrypto();
 
-    if (crypto == NULL || crypto->initCheck() != OK) {
+    if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
         return NULL;
     }
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
new file mode 100644
index 0000000..c32ba9d
--- /dev/null
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -0,0 +1,1162 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaDrm-JNI"
+#include <utils/Log.h>
+
+#include "android_media_MediaDrm.h"
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_os_Parcel.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <media/IDrm.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+#define FIND_CLASS(var, className) \
+    var = env->FindClass(className); \
+    LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+    var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+    LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+    var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
+    LOG_FATAL_IF(! var, "Unable to find method " fieldName);
+
+#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+    var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
+    LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+    var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
+    LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
+
+
+struct RequestFields {
+    jfieldID data;
+    jfieldID defaultUrl;
+};
+
+struct ArrayListFields {
+    jmethodID init;
+    jmethodID add;
+};
+
+struct HashmapFields {
+    jmethodID init;
+    jmethodID get;
+    jmethodID put;
+    jmethodID entrySet;
+};
+
+struct SetFields {
+    jmethodID iterator;
+};
+
+struct IteratorFields {
+    jmethodID next;
+    jmethodID hasNext;
+};
+
+struct EntryFields {
+    jmethodID getKey;
+    jmethodID getValue;
+};
+
+struct EventTypes {
+    int kEventProvisionRequired;
+    int kEventKeyRequired;
+    int kEventKeyExpired;
+    int kEventVendorDefined;
+} gEventTypes;
+
+struct fields_t {
+    jfieldID context;
+    jmethodID post_event;
+    RequestFields keyRequest;
+    RequestFields provisionRequest;
+    ArrayListFields arraylist;
+    HashmapFields hashmap;
+    SetFields set;
+    IteratorFields iterator;
+    EntryFields entry;
+};
+
+static fields_t gFields;
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class JNIDrmListener: public DrmListener
+{
+public:
+    JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
+    ~JNIDrmListener();
+    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
+private:
+    JNIDrmListener();
+    jclass      mClass;     // Reference to MediaDrm class
+    jobject     mObject;    // Weak ref to MediaDrm Java object to call on
+};
+
+JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
+{
+    // Hold onto the MediaDrm class for use in calling the static method
+    // that posts events to the application thread.
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == NULL) {
+        ALOGE("Can't find android/media/MediaDrm");
+        jniThrowException(env, "java/lang/Exception", NULL);
+        return;
+    }
+    mClass = (jclass)env->NewGlobalRef(clazz);
+
+    // We use a weak reference so the MediaDrm object can be garbage collected.
+    // The reference is only used as a proxy for callbacks.
+    mObject  = env->NewGlobalRef(weak_thiz);
+}
+
+JNIDrmListener::~JNIDrmListener()
+{
+    // remove global references
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->DeleteGlobalRef(mObject);
+    env->DeleteGlobalRef(mClass);
+}
+
+void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
+                            const Parcel *obj)
+{
+    jint jeventType;
+
+    // translate DrmPlugin event types into their java equivalents
+    switch(eventType) {
+        case DrmPlugin::kDrmPluginEventProvisionRequired:
+            jeventType = gEventTypes.kEventProvisionRequired;
+            break;
+        case DrmPlugin::kDrmPluginEventKeyNeeded:
+            jeventType = gEventTypes.kEventKeyRequired;
+            break;
+        case DrmPlugin::kDrmPluginEventKeyExpired:
+            jeventType = gEventTypes.kEventKeyExpired;
+            break;
+        case DrmPlugin::kDrmPluginEventVendorDefined:
+            jeventType = gEventTypes.kEventVendorDefined;
+            break;
+        default:
+            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+            return;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    if (obj && obj->dataSize() > 0) {
+        jobject jParcel = createJavaParcelObject(env);
+        if (jParcel != NULL) {
+            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
+            nativeParcel->setData(obj->data(), obj->dataSize());
+            env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
+                    jeventType, extra, jParcel);
+        }
+    }
+
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred while notifying an event.");
+        LOGW_EX(env);
+        env->ExceptionClear();
+    }
+}
+
+
+static bool throwExceptionAsNecessary(
+        JNIEnv *env, status_t err, const char *msg = NULL) {
+
+    if (err == BAD_VALUE) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+        return true;
+    } else if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException", msg);
+        return true;
+    }
+    return false;
+}
+
+static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
+    JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
+    return jdrm ? jdrm->getDrm() : NULL;
+}
+
+JDrm::JDrm(
+        JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
+    mObject = env->NewWeakGlobalRef(thiz);
+    mDrm = MakeDrm(uuid);
+    if (mDrm != NULL) {
+        mDrm->setListener(this);
+    }
+}
+
+JDrm::~JDrm() {
+    mDrm.clear();
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteWeakGlobalRef(mObject);
+    mObject = NULL;
+}
+
+// static
+sp<IDrm> JDrm::MakeDrm() {
+    sp<IServiceManager> sm = defaultServiceManager();
+
+    sp<IBinder> binder =
+        sm->getService(String16("media.player"));
+
+    sp<IMediaPlayerService> service =
+        interface_cast<IMediaPlayerService>(binder);
+
+    if (service == NULL) {
+        return NULL;
+    }
+
+    sp<IDrm> drm = service->makeDrm();
+
+    if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
+        return NULL;
+    }
+
+    return drm;
+}
+
+// static
+sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
+    sp<IDrm> drm = MakeDrm();
+
+    if (drm == NULL) {
+        return NULL;
+    }
+
+    status_t err = drm->createPlugin(uuid);
+
+    if (err != OK) {
+        return NULL;
+    }
+
+    return drm;
+}
+
+status_t JDrm::setListener(const sp<DrmListener>& listener) {
+    Mutex::Autolock lock(mLock);
+    mListener = listener;
+    return OK;
+}
+
+void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
+    sp<DrmListener> listener;
+    mLock.lock();
+    listener = mListener;
+    mLock.unlock();
+
+    if (listener != NULL) {
+        Mutex::Autolock lock(mNotifyLock);
+        listener->notify(eventType, extra, obj);
+    }
+}
+
+
+// static
+bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
+    sp<IDrm> drm = MakeDrm();
+
+    if (drm == NULL) {
+        return false;
+    }
+
+    return drm->isCryptoSchemeSupported(uuid);
+}
+
+status_t JDrm::initCheck() const {
+    return mDrm == NULL ? NO_INIT : OK;
+}
+
+// JNI conversion utilities
+static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
+    Vector<uint8_t> vector;
+    size_t length = env->GetArrayLength(byteArray);
+    vector.insertAt((size_t)0, length);
+    env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
+    return vector;
+}
+
+static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
+    size_t length = vector.size();
+    jbyteArray result = env->NewByteArray(length);
+    if (result != NULL) {
+        env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
+    }
+    return result;
+}
+
+static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
+    String8 result;
+
+    const char *s = env->GetStringUTFChars(jstr, NULL);
+    if (s) {
+        result = s;
+        env->ReleaseStringUTFChars(jstr, s);
+    }
+    return result;
+}
+
+/*
+    import java.util.HashMap;
+    import java.util.Set;
+    import java.Map.Entry;
+    import jav.util.Iterator;
+
+    HashMap<k, v> hm;
+    Set<Entry<k, v> > s = hm.entrySet();
+    Iterator i = s.iterator();
+    Entry e = s.next();
+*/
+
+static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
+    jclass clazz;
+    FIND_CLASS(clazz, "java/lang/String");
+    KeyedVector<String8, String8> keyedVector;
+
+    jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
+    if (entrySet) {
+        jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
+        if (iterator) {
+            jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
+            while (hasNext) {
+                jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
+                if (entry) {
+                    jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
+                    if (!env->IsInstanceOf(obj, clazz)) {
+                        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+                    }
+                    jstring jkey = static_cast<jstring>(obj);
+
+                    obj = env->CallObjectMethod(entry, gFields.entry.getValue);
+                    if (!env->IsInstanceOf(obj, clazz)) {
+                        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+                    }
+                    jstring jvalue = static_cast<jstring>(obj);
+
+                    String8 key = JStringToString8(env, jkey);
+                    String8 value = JStringToString8(env, jvalue);
+                    keyedVector.add(key, value);
+
+                    env->DeleteLocalRef(jkey);
+                    env->DeleteLocalRef(jvalue);
+                    hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
+                }
+                env->DeleteLocalRef(entry);
+            }
+            env->DeleteLocalRef(iterator);
+        }
+        env->DeleteLocalRef(entrySet);
+    }
+    return keyedVector;
+}
+
+static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
+    jclass clazz;
+    FIND_CLASS(clazz, "java/util/HashMap");
+    jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
+    for (size_t i = 0; i < map.size(); ++i) {
+        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
+        jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
+        env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
+        env->DeleteLocalRef(jkey);
+        env->DeleteLocalRef(jvalue);
+    }
+    return hashMap;
+}
+
+static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
+                                                   List<Vector<uint8_t> > list) {
+    jclass clazz;
+    FIND_CLASS(clazz, "java/util/ArrayList");
+    jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
+    List<Vector<uint8_t> >::iterator iter = list.begin();
+    while (iter != list.end()) {
+        jbyteArray byteArray = VectorToJByteArray(env, *iter);
+        env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
+        env->DeleteLocalRef(byteArray);
+        iter++;
+    }
+
+    return arrayList;
+}
+
+}  // namespace android
+
+using namespace android;
+
+static sp<JDrm> setDrm(
+        JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
+    sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
+    if (drm != NULL) {
+        drm->incStrong(thiz);
+    }
+    if (old != NULL) {
+        old->decStrong(thiz);
+    }
+    env->SetIntField(thiz, gFields.context, (int)drm.get());
+
+    return old;
+}
+
+static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
+{
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return false;
+    }
+
+    if (jsessionId == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return false;
+    }
+    return true;
+}
+
+static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
+    sp<JDrm> drm = setDrm(env, thiz, NULL);
+    if (drm != NULL) {
+        drm->setListener(NULL);
+    }
+}
+
+static void android_media_MediaDrm_native_init(JNIEnv *env) {
+    jclass clazz;
+    FIND_CLASS(clazz, "android/media/MediaDrm");
+    GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
+    GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
+                         "(Ljava/lang/Object;IILjava/lang/Object;)V");
+
+    jfieldID field;
+    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+    gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+    gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+    gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_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;");
+
+    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;");
+
+    FIND_CLASS(clazz, "java/util/ArrayList");
+    GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
+    GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
+
+    FIND_CLASS(clazz, "java/util/HashMap");
+    GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
+    GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+    GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
+                  "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+    GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
+
+    FIND_CLASS(clazz, "java/util/Set");
+    GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
+
+    FIND_CLASS(clazz, "java/util/Iterator");
+    GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
+    GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
+
+    FIND_CLASS(clazz, "java/util/Map$Entry");
+    GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
+    GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
+}
+
+static void android_media_MediaDrm_native_setup(
+        JNIEnv *env, jobject thiz,
+        jobject weak_this, jbyteArray uuidObj) {
+
+    if (uuidObj == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
+
+    if (uuid.size() != 16) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
+
+    status_t err = drm->initCheck();
+
+    if (err != OK) {
+        jniThrowException(
+                env,
+                "android/media/MediaDrmException",
+                "Failed to instantiate drm object.");
+        return;
+    }
+
+    sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
+    drm->setListener(listener);
+    setDrm(env, thiz, drm);
+}
+
+static void android_media_MediaDrm_native_finalize(
+        JNIEnv *env, jobject thiz) {
+    android_media_MediaDrm_release(env, thiz);
+}
+
+static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
+        JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
+
+    if (uuidObj == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return false;
+    }
+
+    Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
+
+    if (uuid.size() != 16) {
+        jniThrowException(
+                env,
+                "java/lang/IllegalArgumentException",
+                NULL);
+        return false;
+    }
+
+    return JDrm::IsCryptoSchemeSupported(uuid.array());
+}
+
+static jbyteArray android_media_MediaDrm_openSession(
+    JNIEnv *env, jobject thiz) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId;
+    status_t err = drm->openSession(sessionId);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
+        return NULL;
+    }
+
+    return VectorToJByteArray(env, sessionId);
+}
+
+static void android_media_MediaDrm_closeSession(
+    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+    status_t err = drm->closeSession(sessionId);
+
+    throwExceptionAsNecessary(env, err, "Failed to close session");
+}
+
+static jobject android_media_MediaDrm_getKeyRequest(
+    JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
+    jstring jmimeType, jint jkeyType, jobject joptParams) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+    Vector<uint8_t> initData;
+    if (jinitData != NULL) {
+        initData = JByteArrayToVector(env, jinitData);
+    }
+
+    String8 mimeType;
+    if (jmimeType != NULL) {
+        mimeType = JStringToString8(env, jmimeType);
+    }
+
+    DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)jkeyType;
+
+    KeyedVector<String8, String8> optParams;
+    if (joptParams != NULL) {
+        optParams = HashMapToKeyedVector(env, joptParams);
+    }
+
+    Vector<uint8_t> request;
+    String8 defaultUrl;
+
+    status_t err = drm->getKeyRequest(sessionId, initData, mimeType,
+                                          keyType, optParams, request, defaultUrl);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to get key request")) {
+        return NULL;
+    }
+
+    // Fill out return obj
+    jclass clazz;
+    FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
+
+    jobject keyObj = NULL;
+
+    if (clazz) {
+        keyObj = env->AllocObject(clazz);
+        jbyteArray jrequest = VectorToJByteArray(env, request);
+        env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
+
+        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+        env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
+    }
+
+    return keyObj;
+}
+
+static jbyteArray android_media_MediaDrm_provideKeyResponse(
+    JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+    if (jresponse == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+    Vector<uint8_t> keySetId;
+
+    status_t err = drm->provideKeyResponse(sessionId, response, keySetId);
+
+    throwExceptionAsNecessary(env, err, "Failed to handle key response");
+    return VectorToJByteArray(env, keySetId);
+}
+
+static void android_media_MediaDrm_removeKeys(
+    JNIEnv *env, jobject thiz, jbyteArray jkeysetId) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (jkeysetId == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
+
+    status_t err = drm->removeKeys(keySetId);
+
+    throwExceptionAsNecessary(env, err, "Failed to remove keys");
+}
+
+static void android_media_MediaDrm_restoreKeys(
+    JNIEnv *env, jobject thiz, jbyteArray jsessionId,
+    jbyteArray jkeysetId) {
+
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return;
+    }
+
+    if (jkeysetId == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    Vector<uint8_t> keySetId(JByteArrayToVector(env, jkeysetId));
+
+    status_t err = drm->restoreKeys(sessionId, keySetId);
+
+    throwExceptionAsNecessary(env, err, "Failed to restore keys");
+}
+
+static jobject android_media_MediaDrm_queryKeyStatus(
+    JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+    KeyedVector<String8, String8> infoMap;
+
+    status_t err = drm->queryKeyStatus(sessionId, infoMap);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to query key status")) {
+        return NULL;
+    }
+
+    return KeyedVectorToHashMap(env, infoMap);
+}
+
+static jobject android_media_MediaDrm_getProvisionRequest(
+    JNIEnv *env, jobject thiz) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    Vector<uint8_t> request;
+    String8 defaultUrl;
+
+    status_t err = drm->getProvisionRequest(request, defaultUrl);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
+        return NULL;
+    }
+
+    // Fill out return obj
+    jclass clazz;
+    FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
+
+    jobject provisionObj = NULL;
+
+    if (clazz) {
+        provisionObj = env->AllocObject(clazz);
+        jbyteArray jrequest = VectorToJByteArray(env, request);
+        env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
+
+        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+        env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
+    }
+
+    return provisionObj;
+}
+
+static void android_media_MediaDrm_provideProvisionResponse(
+    JNIEnv *env, jobject thiz, jbyteArray jresponse) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (jresponse == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+
+    status_t err = drm->provideProvisionResponse(response);
+
+    throwExceptionAsNecessary(env, err, "Failed to handle provision response");
+}
+
+static jobject android_media_MediaDrm_getSecureStops(
+    JNIEnv *env, jobject thiz) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    List<Vector<uint8_t> > secureStops;
+
+    status_t err = drm->getSecureStops(secureStops);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
+        return NULL;
+    }
+
+    return ListOfVectorsToArrayListOfByteArray(env, secureStops);
+}
+
+static void android_media_MediaDrm_releaseSecureStops(
+    JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
+
+    status_t err = drm->releaseSecureStops(ssRelease);
+
+    throwExceptionAsNecessary(env, err, "Failed to release secure stops");
+}
+
+static jstring android_media_MediaDrm_getPropertyString(
+    JNIEnv *env, jobject thiz, jstring jname) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    if (jname == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
+    String8 name = JStringToString8(env, jname);
+    String8 value;
+
+    status_t err = drm->getPropertyString(name, value);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
+        return NULL;
+    }
+
+    return env->NewStringUTF(value.string());
+}
+
+static jbyteArray android_media_MediaDrm_getPropertyByteArray(
+    JNIEnv *env, jobject thiz, jstring jname) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    if (jname == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
+    String8 name = JStringToString8(env, jname);
+    Vector<uint8_t> value;
+
+    status_t err = drm->getPropertyByteArray(name, value);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
+        return NULL;
+    }
+
+    return VectorToJByteArray(env, value);
+}
+
+static void android_media_MediaDrm_setPropertyString(
+    JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (jname == NULL || jvalue == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    String8 name = JStringToString8(env, jname);
+    String8 value = JStringToString8(env, jvalue);
+
+    status_t err = drm->setPropertyString(name, value);
+
+    throwExceptionAsNecessary(env, err, "Failed to set property");
+}
+
+static void android_media_MediaDrm_setPropertyByteArray(
+    JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
+    sp<IDrm> drm = GetDrm(env, thiz);
+
+    if (drm == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (jname == NULL || jvalue == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    String8 name = JStringToString8(env, jname);
+    Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
+
+    status_t err = drm->setPropertyByteArray(name, value);
+
+    throwExceptionAsNecessary(env, err, "Failed to set property");
+}
+
+static void android_media_MediaDrm_setCipherAlgorithmNative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jstring jalgorithm) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return;
+    }
+
+    if (jalgorithm == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    String8 algorithm = JStringToString8(env, jalgorithm);
+
+    status_t err = drm->setCipherAlgorithm(sessionId, algorithm);
+
+    throwExceptionAsNecessary(env, err, "Failed to set cipher algorithm");
+}
+
+static void android_media_MediaDrm_setMacAlgorithmNative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jstring jalgorithm) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return;
+    }
+
+    if (jalgorithm == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    String8 algorithm = JStringToString8(env, jalgorithm);
+
+    status_t err = drm->setMacAlgorithm(sessionId, algorithm);
+
+    throwExceptionAsNecessary(env, err, "Failed to set mac algorithm");
+}
+
+
+static jbyteArray android_media_MediaDrm_encryptNative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+    Vector<uint8_t> input(JByteArrayToVector(env, jinput));
+    Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
+    Vector<uint8_t> output;
+
+    status_t err = drm->encrypt(sessionId, keyId, input, iv, output);
+
+    throwExceptionAsNecessary(env, err, "Failed to encrypt");
+
+    return VectorToJByteArray(env, output);
+}
+
+static jbyteArray android_media_MediaDrm_decryptNative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jbyteArray jkeyId, jbyteArray jinput, jbyteArray jiv) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    if (jkeyId == NULL || jinput == NULL || jiv == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+    Vector<uint8_t> input(JByteArrayToVector(env, jinput));
+    Vector<uint8_t> iv(JByteArrayToVector(env, jiv));
+    Vector<uint8_t> output;
+
+    status_t err = drm->decrypt(sessionId, keyId, input, iv, output);
+    throwExceptionAsNecessary(env, err, "Failed to decrypt");
+
+    return VectorToJByteArray(env, output);
+}
+
+static jbyteArray android_media_MediaDrm_signNative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jbyteArray jkeyId, jbyteArray jmessage) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    if (jkeyId == NULL || jmessage == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+    Vector<uint8_t> signature;
+
+    status_t err = drm->sign(sessionId, keyId, message, signature);
+
+    throwExceptionAsNecessary(env, err, "Failed to sign");
+
+    return VectorToJByteArray(env, signature);
+}
+
+static jboolean android_media_MediaDrm_verifyNative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jbyteArray jkeyId, jbyteArray jmessage, jbyteArray jsignature) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return false;
+    }
+
+    if (jkeyId == NULL || jmessage == NULL || jsignature == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return false;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    Vector<uint8_t> keyId(JByteArrayToVector(env, jkeyId));
+    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+    Vector<uint8_t> signature(JByteArrayToVector(env, jsignature));
+    bool match;
+
+    status_t err = drm->verify(sessionId, keyId, message, signature, match);
+
+    throwExceptionAsNecessary(env, err, "Failed to verify");
+    return match;
+}
+
+
+static JNINativeMethod gMethods[] = {
+    { "release", "()V", (void *)android_media_MediaDrm_release },
+    { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
+
+    { "native_setup", "(Ljava/lang/Object;[B)V",
+      (void *)android_media_MediaDrm_native_setup },
+
+    { "native_finalize", "()V",
+      (void *)android_media_MediaDrm_native_finalize },
+
+    { "isCryptoSchemeSupportedNative", "([B)Z",
+      (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
+
+    { "openSession", "()[B",
+      (void *)android_media_MediaDrm_openSession },
+
+    { "closeSession", "([B)V",
+      (void *)android_media_MediaDrm_closeSession },
+
+    { "getKeyRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
+      "Landroid/media/MediaDrm$KeyRequest;",
+      (void *)android_media_MediaDrm_getKeyRequest },
+
+    { "provideKeyResponse", "([B[B)[B",
+      (void *)android_media_MediaDrm_provideKeyResponse },
+
+    { "removeKeys", "([B)V",
+      (void *)android_media_MediaDrm_removeKeys },
+
+    { "restoreKeys", "([B[B)V",
+      (void *)android_media_MediaDrm_restoreKeys },
+
+    { "queryKeyStatus", "([B)Ljava/util/HashMap;",
+      (void *)android_media_MediaDrm_queryKeyStatus },
+
+    { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
+      (void *)android_media_MediaDrm_getProvisionRequest },
+
+    { "provideProvisionResponse", "([B)V",
+      (void *)android_media_MediaDrm_provideProvisionResponse },
+
+    { "getSecureStops", "()Ljava/util/List;",
+      (void *)android_media_MediaDrm_getSecureStops },
+
+    { "releaseSecureStops", "([B)V",
+      (void *)android_media_MediaDrm_releaseSecureStops },
+
+    { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
+      (void *)android_media_MediaDrm_getPropertyString },
+
+    { "getPropertyByteArray", "(Ljava/lang/String;)[B",
+      (void *)android_media_MediaDrm_getPropertyByteArray },
+
+    { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
+      (void *)android_media_MediaDrm_setPropertyString },
+
+    { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
+      (void *)android_media_MediaDrm_setPropertyByteArray },
+
+    { "setCipherAlgorithmNative",
+      "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
+      (void *)android_media_MediaDrm_setCipherAlgorithmNative },
+
+    { "setMacAlgorithmNative",
+      "(Landroid/media/MediaDrm;[BLjava/lang/String;)V",
+      (void *)android_media_MediaDrm_setMacAlgorithmNative },
+
+    { "encryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
+      (void *)android_media_MediaDrm_encryptNative },
+
+    { "decryptNative", "(Landroid/media/MediaDrm;[B[B[B[B)[B",
+      (void *)android_media_MediaDrm_decryptNative },
+
+    { "signNative", "(Landroid/media/MediaDrm;[B[B[B)[B",
+      (void *)android_media_MediaDrm_signNative },
+
+    { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
+      (void *)android_media_MediaDrm_verifyNative },
+};
+
+int register_android_media_Drm(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+                "android/media/MediaDrm", gMethods, NELEM(gMethods));
+}
+
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
new file mode 100644
index 0000000..9b3917f
--- /dev/null
+++ b/media/jni/android_media_MediaDrm.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_DRM_H_
+#define _ANDROID_MEDIA_DRM_H_
+
+#include "jni.h"
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/IDrm.h>
+#include <media/IDrmClient.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IDrm;
+
+class DrmListener: virtual public RefBase
+{
+public:
+    virtual void notify(DrmPlugin::EventType eventType, int extra,
+                        const Parcel *obj) = 0;
+};
+
+struct JDrm : public BnDrmClient {
+    static bool IsCryptoSchemeSupported(const uint8_t uuid[16]);
+
+    JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);
+
+    status_t initCheck() const;
+    sp<IDrm> getDrm() { return mDrm; }
+
+    void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
+    status_t setListener(const sp<DrmListener>& listener);
+
+protected:
+    virtual ~JDrm();
+
+private:
+    jweak mObject;
+    sp<IDrm> mDrm;
+
+    sp<DrmListener> mListener;
+    Mutex mNotifyLock;
+    Mutex mLock;
+
+    static sp<IDrm> MakeDrm();
+    static sp<IDrm> MakeDrm(const uint8_t uuid[16]);
+
+    DISALLOW_EVIL_CONSTRUCTORS(JDrm);
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_DRM_H_
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 23949fa..1704d5c 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -162,6 +162,18 @@
     return ConvertMessageToMap(env, msg, format);
 }
 
+status_t JMediaExtractor::getFileFormat(jobject *format) const {
+    sp<AMessage> msg;
+    status_t err;
+    if ((err = mImpl->getFileFormat(&msg)) != OK) {
+        return err;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    return ConvertMessageToMap(env, msg, format);
+}
+
 status_t JMediaExtractor::selectTrack(size_t index) {
     return mImpl->selectTrack(index);
 }
@@ -339,6 +351,26 @@
     return format;
 }
 
+static jobject android_media_MediaExtractor_getFileFormatNative(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    jobject format;
+    status_t err = extractor->getFileFormat(&format);
+
+    if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
+    return format;
+}
+
 static void android_media_MediaExtractor_selectTrack(
         JNIEnv *env, jobject thiz, jint index) {
     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -768,6 +800,9 @@
 
     { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
 
+    { "getFileFormatNative", "()Ljava/util/Map;",
+        (void *)android_media_MediaExtractor_getFileFormatNative },
+
     { "getTrackFormatNative", "(I)Ljava/util/Map;",
         (void *)android_media_MediaExtractor_getTrackFormatNative },
 
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 03900db..ccbad8c 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -45,6 +45,8 @@
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, jobject *format) const;
 
+    status_t getFileFormat(jobject *format) const;
+
     status_t selectTrack(size_t index);
     status_t unselectTrack(size_t index);
 
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
new file mode 100644
index 0000000..7517e85
--- /dev/null
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaMuxer-JNI"
+#include <utils/Log.h>
+
+#include "android_media_Utils.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaMuxer.h>
+
+namespace android {
+
+struct fields_t {
+    jfieldID context;
+    jmethodID arrayID;
+};
+
+static fields_t gFields;
+
+}
+
+using namespace android;
+
+static jint android_media_MediaMuxer_addTrack(
+        JNIEnv *env, jclass clazz, jint nativeObject, jobjectArray keys,
+        jobjectArray values) {
+    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+    if (muxer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Muxer was not set up correctly");
+        return -1;
+    }
+
+    sp<AMessage> trackformat;
+    status_t err = ConvertKeyValueArraysToMessage(env, keys, values,
+                                                  &trackformat);
+    if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "ConvertKeyValueArraysToMessage got an error");
+        return err;
+    }
+
+    // Return negative value when errors happen in addTrack.
+    jint trackIndex = muxer->addTrack(trackformat);
+
+    if (trackIndex < 0) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to add the track to the muxer");
+        return -1;
+    }
+    return trackIndex;
+}
+
+static void android_media_MediaMuxer_writeSampleData(
+        JNIEnv *env, jclass clazz, jint nativeObject, jint trackIndex,
+        jobject byteBuf, jint offset, jint size, jlong timeUs, jint flags) {
+    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+    if (muxer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Muxer was not set up correctly");
+        return;
+    }
+
+    // Try to convert the incoming byteBuffer into ABuffer
+    void *dst = env->GetDirectBufferAddress(byteBuf);
+
+    jlong dstSize;
+    jbyteArray byteArray = NULL;
+
+    if (dst == NULL) {
+
+        byteArray =
+            (jbyteArray)env->CallObjectMethod(byteBuf, gFields.arrayID);
+
+        if (byteArray == NULL) {
+            jniThrowException(env, "java/lang/IllegalArgumentException",
+                              "byteArray is null");
+            return;
+        }
+
+        jboolean isCopy;
+        dst = env->GetByteArrayElements(byteArray, &isCopy);
+
+        dstSize = env->GetArrayLength(byteArray);
+    } else {
+        dstSize = env->GetDirectBufferCapacity(byteBuf);
+    }
+
+    if (dstSize < (offset + size)) {
+        ALOGE("writeSampleData saw wrong dstSize %lld, size  %d, offset %d",
+              dstSize, size, offset);
+        if (byteArray != NULL) {
+            env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
+        }
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "sample has a wrong size");
+        return;
+    }
+
+    sp<ABuffer> buffer = new ABuffer((char *)dst + offset, size);
+
+    status_t err = muxer->writeSampleData(buffer, trackIndex, timeUs, flags);
+
+    if (byteArray != NULL) {
+        env->ReleaseByteArrayElements(byteArray, (jbyte *)dst, 0);
+    }
+
+    if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "writeSampleData returned an error");
+    }
+    return;
+}
+
+// Constructor counterpart.
+static jint android_media_MediaMuxer_native_setup(
+        JNIEnv *env, jclass clazz, jobject fileDescriptor,
+        jint format) {
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    ALOGV("native_setup: fd %d", fd);
+
+    MediaMuxer::OutputFormat fileFormat =
+        static_cast<MediaMuxer::OutputFormat>(format);
+    sp<MediaMuxer> muxer = new MediaMuxer(fd, fileFormat);
+    muxer->incStrong(clazz);
+    return int(muxer.get());
+}
+
+static void android_media_MediaMuxer_setOrientationHint(
+        JNIEnv *env, jclass clazz, jint nativeObject, jint degrees) {
+    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+    if (muxer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Muxer was not set up correctly");
+        return;
+    }
+    status_t err = muxer->setOrientationHint(degrees);
+
+    if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to set orientation hint");
+        return;
+    }
+
+}
+
+static void android_media_MediaMuxer_start(JNIEnv *env, jclass clazz,
+                                           jint nativeObject) {
+    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+    if (muxer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Muxer was not set up correctly");
+        return;
+    }
+    status_t err = muxer->start();
+
+    if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to start the muxer");
+        return;
+    }
+
+}
+
+static void android_media_MediaMuxer_stop(JNIEnv *env, jclass clazz,
+                                          jint nativeObject) {
+    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+    if (muxer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Muxer was not set up correctly");
+        return;
+    }
+
+    status_t err = muxer->stop();
+
+    if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "Failed to stop the muxer");
+        return;
+    }
+}
+
+static void android_media_MediaMuxer_native_release(
+        JNIEnv *env, jclass clazz, jint nativeObject) {
+    sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+    if (muxer != NULL) {
+        muxer->decStrong(clazz);
+    }
+}
+
+static JNINativeMethod gMethods[] = {
+
+    { "nativeAddTrack", "(I[Ljava/lang/String;[Ljava/lang/Object;)I",
+        (void *)android_media_MediaMuxer_addTrack },
+
+    { "nativeSetOrientationHint", "(II)V",
+        (void *)android_media_MediaMuxer_setOrientationHint},
+
+    { "nativeStart", "(I)V", (void *)android_media_MediaMuxer_start},
+
+    { "nativeWriteSampleData", "(IILjava/nio/ByteBuffer;IIJI)V",
+        (void *)android_media_MediaMuxer_writeSampleData },
+
+    { "nativeStop", "(I)V", (void *)android_media_MediaMuxer_stop},
+
+    { "nativeSetup", "(Ljava/io/FileDescriptor;I)I",
+        (void *)android_media_MediaMuxer_native_setup },
+
+    { "nativeRelease", "(I)V",
+        (void *)android_media_MediaMuxer_native_release },
+
+};
+
+// This function only registers the native methods, and is called from
+// JNI_OnLoad in android_media_MediaPlayer.cpp
+int register_android_media_MediaMuxer(JNIEnv *env) {
+    int err = AndroidRuntime::registerNativeMethods(env,
+                "android/media/MediaMuxer", gMethods, NELEM(gMethods));
+
+    jclass clazz = env->FindClass("android/media/MediaMuxer");
+    CHECK(clazz != NULL);
+
+    gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+    CHECK(gFields.context != NULL);
+
+    jclass byteBufClass = env->FindClass("java/nio/ByteBuffer");
+    CHECK(byteBufClass != NULL);
+
+    gFields.arrayID =
+        env->GetMethodID(byteBufClass, "array", "()[B");
+    CHECK(gFields.arrayID != NULL);
+
+    return err;
+}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 7421022..c5098ce 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -136,10 +136,10 @@
     Mutex::Autolock l(sLock);
     sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
     if (player.get()) {
-        player->incStrong(thiz);
+        player->incStrong((void*)setMediaPlayer);
     }
     if (old != 0) {
-        old->decStrong(thiz);
+        old->decStrong((void*)setMediaPlayer);
     }
     env->SetIntField(thiz, fields.context, (int)player.get());
     return old;
@@ -252,7 +252,7 @@
 
     sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz);
     if (old_st != NULL) {
-        old_st->decStrong(thiz);
+        old_st->decStrong((void*)decVideoSurfaceRef);
     }
 }
 
@@ -279,7 +279,7 @@
                     "The surface does not have a binding SurfaceTexture!");
                 return;
             }
-            new_st->incStrong(thiz);
+            new_st->incStrong((void*)decVideoSurfaceRef);
         } else {
             jniThrowException(env, "java/lang/IllegalArgumentException",
                     "The surface has been released");
@@ -879,10 +879,12 @@
 }
 
 extern int register_android_media_Crypto(JNIEnv *env);
+extern int register_android_media_Drm(JNIEnv *env);
 extern int register_android_media_MediaCodec(JNIEnv *env);
 extern int register_android_media_MediaExtractor(JNIEnv *env);
 extern int register_android_media_MediaCodecList(JNIEnv *env);
 extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
+extern int register_android_media_MediaMuxer(JNIEnv *env);
 extern int register_android_media_MediaRecorder(JNIEnv *env);
 extern int register_android_media_MediaScanner(JNIEnv *env);
 extern int register_android_media_ResampleInputStream(JNIEnv *env);
@@ -963,6 +965,11 @@
         goto bail;
     }
 
+    if (register_android_media_MediaMuxer(env) < 0) {
+        ALOGE("ERROR: MediaMuxer native registration failed");
+        goto bail;
+    }
+
     if (register_android_media_MediaCodecList(env) < 0) {
         ALOGE("ERROR: MediaCodec native registration failed");
         goto bail;
@@ -973,6 +980,11 @@
         goto bail;
     }
 
+    if (register_android_media_Drm(env) < 0) {
+        ALOGE("ERROR: MediaDrm native registration failed");
+        goto bail;
+    }
+
     /* success -- return valid version number */
     result = JNI_VERSION_1_4;
 
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 4ebbbde..9888591 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -327,7 +327,7 @@
         }
 
         ALOGI("prepare: surface=%p", native_surface.get());
-        if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.")) {
+        if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface->getIGraphicBufferProducer()), "java/lang/RuntimeException", "setPreviewSurface failed.")) {
             return;
         }
     }
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index bc65de5..fbd5d21 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -775,7 +775,8 @@
     env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
 
     jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
-    info.mDateModified = longValues[0];
+    info.mDateCreated = longValues[0];
+    info.mDateModified = longValues[1];
     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
 
 //    info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
index b5d8b7b..3b1fb19 100644
--- a/media/jni/audioeffect/Android.mk
+++ b/media/jni/audioeffect/Android.mk
@@ -6,6 +6,7 @@
 	android_media_Visualizer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+	liblog \
 	libcutils \
 	libutils \
 	libandroid_runtime \
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index 040d2ab..6be7fdd 100644
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -52,6 +52,7 @@
     libaudioutils \
     libbinder \
     libcutils \
+    liblog \
     libdl \
     libgui \
     libmedia \
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 9b11bfa..5835b9f 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -5,6 +5,7 @@
 	android_media_SoundPool.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+	liblog \
 	libcutils \
 	libutils \
 	libandroid_runtime \
diff --git a/media/libdrm/mobile1/Android.mk b/media/libdrm/mobile1/Android.mk
index b07d91c..7356f46 100644
--- a/media/libdrm/mobile1/Android.mk
+++ b/media/libdrm/mobile1/Android.mk
@@ -44,6 +44,7 @@
 LOCAL_SHARED_LIBRARIES :=   \
     libutils                \
     libcutils               \
+    liblog                  \
     libcrypto
 
 LOCAL_MODULE := libdrm1
@@ -69,12 +70,13 @@
     $(LOCAL_PATH)/include/parser \
     $(JNI_H_INCLUDE)    \
     $(call include-path-for, system-core)/cutils
-	
+
 
 LOCAL_SHARED_LIBRARIES := libdrm1 \
     libnativehelper               \
     libutils                      \
-    libcutils
+    libcutils                     \
+    liblog
 
 LOCAL_MODULE := libdrm1_jni
 
diff --git a/media/mca/filterfw/Android.mk b/media/mca/filterfw/Android.mk
index 1d69799..2a9448d 100644
--- a/media/mca/filterfw/Android.mk
+++ b/media/mca/filterfw/Android.mk
@@ -37,6 +37,7 @@
                           libdl \
                           libcutils \
                           libutils \
+                          liblog \
                           libandroid \
                           libjnigraphics \
                           libmedia
@@ -48,5 +49,3 @@
 LOCAL_PRELINK_MODULE := false
 
 include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/media/mca/filterpacks/Android.mk b/media/mca/filterpacks/Android.mk
index 6166b1e..6e54f60 100644
--- a/media/mca/filterpacks/Android.mk
+++ b/media/mca/filterpacks/Android.mk
@@ -46,10 +46,8 @@
                    native/imageproc/invert.c \
                    native/imageproc/to_rgba.c
 
-LOCAL_SHARED_LIBRARIES := libutils libfilterfw
+LOCAL_SHARED_LIBRARIES := liblog libutils libfilterfw
 
 LOCAL_PRELINK_MODULE := false
 
 include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java
index 5c74552..fa60ca6 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java
@@ -43,7 +43,7 @@
     public static int mBitRate = profile.videoBitRate;
     public static boolean mRemoveVideo = true;
     public static int mDuration = 60 * 1000; // 60 seconds
-    public static int mTimeLapseDuration = 180 * 1000; // 3 minutes
+    public static int mTimeLapseDuration = 15 * 60 * 1000; // 15 minutes
     public static double mCaptureRate = 0.5; // 2 sec timelapse interval
 
     @Override
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java
index a80fc13..53eb990 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaTestUtil.java
@@ -101,7 +101,9 @@
             Log.v(TAG, e.toString());
         }
         String[] poList = memoryUsage.split("\r|\n|\r\n");
-        String memusage = poList[1].concat("\n");
+        // Skip the first two lines since there
+        // is a new media.log introudced recently.
+        String memusage = poList[2].concat("\n");
         return memusage;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
index 7967ce7..e232338 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
@@ -42,6 +42,7 @@
     private final static int WAIT_FOR_LOOPER_TO_INITIALIZE_MS = 60000;  // 60s
     private int[] ringtoneMode = {AudioManager.RINGER_MODE_NORMAL,
              AudioManager.RINGER_MODE_SILENT, AudioManager.RINGER_MODE_VIBRATE};
+    private boolean mUseFixedVolume;
 
     public MediaAudioManagerTest() {
         super("com.android.mediaframeworktest", MediaFrameworkTest.class);
@@ -65,6 +66,10 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        mUseFixedVolume = getActivity().getResources().getBoolean(
+                com.android.internal.R.bool.config_useFixedVolume);
+
         synchronized(mLooperLock) {
             initializeAudioManagerWithLooper();
             try {
@@ -91,10 +96,12 @@
 
      public boolean validateSetRingTone(int i) {
          int getRingtone = mAudioManager.getRingerMode();
-         if (i != getRingtone)
-             return false;
-         else
-             return true;
+
+         if (mUseFixedVolume) {
+             return (getRingtone == AudioManager.RINGER_MODE_NORMAL);
+         } else {
+             return (getRingtone == i);
+         }
      }
 
      // Test case 1: Simple test case to validate the set ringtone mode
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 1c60401..be12c7f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -328,7 +328,15 @@
             Log.v(TAG, e.toString());
         }
         String[] poList = memoryUsage.split("\r|\n|\r\n");
-        String memusage = poList[1].concat("\n");
+        // A new media.log is enabled with ro.test_harness is set.
+        // The output of "ps mediaserver" will include the
+        // media.log process in the first line. Update the parsing
+        // to only read the thrid line.
+        // Smaple ps mediaserver output:
+        // USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
+        // media     131   1     13676  4796  ffffffff 400b1bd0 S media.log
+        // media     219   131   37768  6892  ffffffff 400b236c S /system/bin/mediaserver
+        String memusage = poList[2].concat("\n");
         return memusage;
     }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index 6eb9891..199f179 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -50,16 +50,10 @@
     private Camera mCamera;
 
     private static final int CAMERA_ID = 0;
-    private static final int NUMBER_OF_CAMERA_STRESS_LOOPS = 100;
-    private static final int NUMBER_OF_RECORDER_STRESS_LOOPS = 100;
-    private static final int NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS = 50;
-    private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 200;
-    private static final int NUMBER_OF_TIME_LAPSE_LOOPS = 25;
-    private static final int TIME_LAPSE_PLAYBACK_WAIT_TIME = 5* 1000; // 5 seconds
+    private static final int NUMBER_OF_TIME_LAPSE_LOOPS = 1;
+    private static final int TIME_LAPSE_PLAYBACK_WAIT_TIME = 30 * 1000; // 30 seconds
     private static final int USE_TEST_RUNNER_PROFILE = -1;
     private static final long WAIT_TIMEOUT = 10 * 1000; // 10 seconds
-    private static final long WAIT_TIME_CAMERA_TEST = 3 * 1000; // 3 seconds
-    private static final long WAIT_TIME_RECORDER_TEST = 6 * 1000; // 6 seconds
     private static final String OUTPUT_FILE_EXT = ".3gp";
     private static final String MEDIA_STRESS_OUTPUT = "mediaStressOutput.txt";
 
@@ -150,158 +144,6 @@
         }
     }
 
-    //Test case for stressing the camera preview.
-    @LargeTest
-    public void testStressCamera() throws Exception {
-        SurfaceHolder mSurfaceHolder;
-        mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
-        Log.v(TAG, "Camera start preview stress test");
-        mOutput.write("Total number of loops:" + NUMBER_OF_CAMERA_STRESS_LOOPS + "\n");
-        try {
-            Log.v(TAG, "Start preview");
-            mOutput.write("No of loop: ");
-
-            for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++) {
-                runOnLooper(new Runnable() {
-                    @Override
-                    public void run() {
-                        mCamera = Camera.open(CAMERA_ID);
-                    }
-                });
-                mCamera.setErrorCallback(mCameraErrorCallback);
-                mCamera.setPreviewDisplay(mSurfaceHolder);
-                mCamera.startPreview();
-                Thread.sleep(WAIT_TIME_CAMERA_TEST);
-                mCamera.stopPreview();
-                mCamera.release();
-                if (i == 0) {
-                    mOutput.write(i + 1);
-                } else {
-                    mOutput.write(String.format(", %d", (i + 1)));
-                }
-            }
-        } catch (Exception e) {
-            Log.e(TAG, e.toString());
-            fail("Camera startup preview stress test");
-        }
-    }
-
-    //Test case for stressing the camera preview.
-    @LargeTest
-    public void testStressRecorder() throws Exception {
-        SurfaceHolder mSurfaceHolder;
-        mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
-        Log.v(TAG, "H263 video record: reset after prepare Stress test");
-        mOutput.write("Total number of loops:" + NUMBER_OF_RECORDER_STRESS_LOOPS + "\n");
-        try {
-            mOutput.write("No of loop: ");
-            Log.v(TAG, "Start preview");
-            for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++) {
-                runOnLooper(new Runnable() {
-                    @Override
-                    public void run() {
-                        mRecorder = new MediaRecorder();
-                    }
-                });
-                Log.v(TAG, "counter = " + i);
-                String fileName = String.format("%s/temp%d%s",
-                        Environment.getExternalStorageDirectory(),
-                        i, OUTPUT_FILE_EXT);
-
-                Log.v(TAG, fileName);
-                mRecorder.setOnErrorListener(mRecorderErrorCallback);
-                mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
-                mRecorder.setOutputFile(fileName);
-                mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate);
-                mRecorder.setVideoSize(176,144);
-                Log.v(TAG, "setEncoder");
-                mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
-                mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
-                Log.v(TAG, "setPreview");
-                mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
-                Log.v(TAG, "prepare");
-                mRecorder.prepare();
-                Log.v(TAG, "before release");
-                Thread.sleep(WAIT_TIME_RECORDER_TEST);
-                mRecorder.reset();
-                mRecorder.release();
-                if (i == 0) {
-                    mOutput.write(i + 1);
-                } else {
-                    mOutput.write(String.format(", %d", (i + 1)));
-                }
-            }
-        } catch (Exception e) {
-            Log.e(TAG, e.toString());
-            fail("H263 video recording stress test");
-        }
-    }
-
-    //Stress test case for switching camera and video recorder preview.
-    @LargeTest
-    public void testStressCameraSwitchRecorder() throws Exception {
-        SurfaceHolder mSurfaceHolder;
-        mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
-        Log.v(TAG, "Camera and video recorder preview switching");
-        mOutput.write("Total number of loops: " +
-                NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n");
-        try {
-            Log.v(TAG, "Start preview");
-            mOutput.write("No of loop: ");
-            for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++) {
-                runOnLooper(new Runnable() {
-                    @Override
-                    public void run() {
-                        mCamera = Camera.open(CAMERA_ID);
-                    }
-                });
-                mCamera.setErrorCallback(mCameraErrorCallback);
-                mCamera.setPreviewDisplay(mSurfaceHolder);
-                mCamera.startPreview();
-                Thread.sleep(WAIT_TIME_CAMERA_TEST);
-                mCamera.stopPreview();
-                mCamera.release();
-                mCamera = null;
-                Log.v(TAG, "release camera");
-                String fileName = String.format("%s/temp%d%s",
-                        Environment.getExternalStorageDirectory(),
-                        i, OUTPUT_FILE_EXT);
-                Log.v(TAG, fileName);
-                runOnLooper(new Runnable() {
-                    @Override
-                    public void run() {
-                        mRecorder = new MediaRecorder();
-                    }
-                });
-                mRecorder.setOnErrorListener(mRecorderErrorCallback);
-                mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
-                mRecorder.setOutputFile(fileName);
-                mRecorder.setVideoFrameRate(MediaRecorderStressTestRunner.mFrameRate);
-                mRecorder.setVideoSize(176,144);
-                Log.v(TAG, "Media recorder setEncoder");
-                mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
-                Log.v(TAG, "mediaRecorder setPreview");
-                mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
-                Log.v(TAG, "prepare");
-                mRecorder.prepare();
-                Log.v(TAG, "before release");
-                Thread.sleep(WAIT_TIME_CAMERA_TEST);
-                mRecorder.release();
-                Log.v(TAG, "release video recorder");
-                if (i == 0) {
-                    mOutput.write(i + 1);
-                } else {
-                    mOutput.write(String.format(", %d", (i + 1)));
-                }
-            }
-        } catch (Exception e) {
-            Log.e(TAG, e.toString());
-            fail("Camera and recorder switch mode");
-        }
-    }
-
     public void validateRecordedVideo(String recordedFile) {
         try {
             MediaPlayer mp = new MediaPlayer();
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 9dcc7ba..ad874c8 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -29,6 +29,7 @@
     libstagefright_foundation \
     libbinder \
     libutils \
+    liblog \
     libjpeg
 
 LOCAL_C_INCLUDES := \
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
index c655ae6..adf0d30 100644
--- a/media/tests/players/Android.mk
+++ b/media/tests/players/Android.mk
@@ -20,7 +20,8 @@
 
 LOCAL_SHARED_LIBRARIES:= \
     libbinder \
-    libutils
+    libutils \
+    liblog
 
 LOCAL_MODULE:= invoke_mock_media_player
 LOCAL_MODULE_TAGS := tests eng
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 00d11da..207cc4b 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -17,6 +17,7 @@
     storage_manager.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+    liblog \
     libcutils \
     libandroidfw \
     libutils \
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index d1e2a9ed..2c9508a 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -447,7 +447,6 @@
 
     // C function EGLBoolean eglPresentationTimeANDROID ( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time )
 
-    /** @hide -- TODO(fadden) unhide this */
     public static native boolean eglPresentationTimeANDROID(
         EGLDisplay dpy,
         EGLSurface sur,
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 54dcaaa..ab7ceb6 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -18,7 +18,6 @@
 
 import java.io.Writer;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGL11;
@@ -30,10 +29,13 @@
 import javax.microedition.khronos.opengles.GL10;
 
 import android.content.Context;
-import android.content.pm.ConfigurationInfo;
-import android.os.SystemProperties;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Choreographer;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
@@ -164,11 +166,26 @@
     private final static String TAG = "GLSurfaceView";
     private final static boolean LOG_ATTACH_DETACH = false;
     private final static boolean LOG_THREADS = false;
-    private final static boolean LOG_PAUSE_RESUME = false;
     private final static boolean LOG_SURFACE = false;
     private final static boolean LOG_RENDERER = false;
     private final static boolean LOG_RENDERER_DRAW_FRAME = false;
     private final static boolean LOG_EGL = false;
+    private final static boolean TRACE_ENABLED = false;
+
+    private final WeakReference<GLSurfaceView> mThisWeakRef =
+            new WeakReference<GLSurfaceView>(this);
+    private GLThread mGLThread;
+    private Renderer mRenderer;
+    private boolean mDetached;
+    private EGLConfigChooser mEGLConfigChooser;
+    private EGLContextFactory mEGLContextFactory;
+    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
+    private GLWrapper mGLWrapper;
+    private int mDebugFlags;
+    private int mEGLContextClientVersion;
+    private boolean mPreserveEGLContextOnPause;
+    private int mUserRenderMode;
+
     /**
      * The renderer only renders
      * when the surface is created, or when {@link #requestRender} is called.
@@ -241,13 +258,7 @@
         // underlying surface is created and destroyed
         SurfaceHolder holder = getHolder();
         holder.addCallback(this);
-        // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
-        // this statement if back-porting to 2.2 or older:
-        // holder.setFormat(PixelFormat.RGB_565);
-        //
-        // setType is not needed for SDK 2.0 or newer. Uncomment this
-        // statement if back-porting this code to older SDKs.
-        // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+        mUserRenderMode = RENDERMODE_CONTINUOUSLY;
     }
 
     /**
@@ -346,15 +357,16 @@
     public void setRenderer(Renderer renderer) {
         checkRenderThreadState();
         if (mEGLConfigChooser == null) {
-            mEGLConfigChooser = new SimpleEGLConfigChooser(true);
+            mEGLConfigChooser = new SimpleEGLConfigChooser(true, mEGLContextClientVersion);
         }
         if (mEGLContextFactory == null) {
-            mEGLContextFactory = new DefaultContextFactory();
+            mEGLContextFactory = new DefaultContextFactory(mEGLContextClientVersion);
         }
         if (mEGLWindowSurfaceFactory == null) {
             mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
         }
         mRenderer = renderer;
+
         mGLThread = new GLThread(mThisWeakRef);
         mGLThread.start();
     }
@@ -420,7 +432,7 @@
      * @param needDepth
      */
     public void setEGLConfigChooser(boolean needDepth) {
-        setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
+        setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth, mEGLContextClientVersion));
     }
 
     /**
@@ -439,7 +451,7 @@
     public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
             int alphaSize, int depthSize, int stencilSize) {
         setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
-                blueSize, alphaSize, depthSize, stencilSize));
+                blueSize, alphaSize, depthSize, stencilSize, mEGLContextClientVersion));
     }
 
     /**
@@ -466,6 +478,13 @@
      * If
      * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied
      * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config.
+     *
+     * This method must be called before:
+     * <ul>
+     * <li>{@link #setEGLConfigChooser(boolean)}
+     * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}
+     * </ul>
+     *
      * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0
      */
     public void setEGLContextClientVersion(int version) {
@@ -490,6 +509,14 @@
      * @see #RENDERMODE_WHEN_DIRTY
      */
     public void setRenderMode(int renderMode) {
+        switch (renderMode) {
+            case RENDERMODE_WHEN_DIRTY:
+            case RENDERMODE_CONTINUOUSLY:
+                break;
+            default:
+                throw new IllegalArgumentException("renderMode");
+        }
+        mUserRenderMode = renderMode;
         mGLThread.setRenderMode(renderMode);
     }
 
@@ -501,7 +528,7 @@
      * @see #RENDERMODE_WHEN_DIRTY
      */
     public int getRenderMode() {
-        return mGLThread.getRenderMode();
+        return mUserRenderMode;
     }
 
     /**
@@ -582,14 +609,8 @@
             Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
         }
         if (mDetached && (mRenderer != null)) {
-            int renderMode = RENDERMODE_CONTINUOUSLY;
-            if (mGLThread != null) {
-                renderMode = mGLThread.getRenderMode();
-            }
             mGLThread = new GLThread(mThisWeakRef);
-            if (renderMode != RENDERMODE_CONTINUOUSLY) {
-                mGLThread.setRenderMode(renderMode);
-            }
+            mGLThread.setRenderMode(mUserRenderMode);
             mGLThread.start();
         }
         mDetached = false;
@@ -761,11 +782,15 @@
         void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
     }
 
-    private class DefaultContextFactory implements EGLContextFactory {
-        private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+    private static class DefaultContextFactory implements EGLContextFactory {
+        private final int mEGLContextClientVersion;
+
+        public DefaultContextFactory(int version) {
+            mEGLContextClientVersion = version;
+        }
 
         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
-            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+            int[] attrib_list = {EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
                     EGL10.EGL_NONE };
 
             return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
@@ -775,9 +800,9 @@
         public void destroyContext(EGL10 egl, EGLDisplay display,
                 EGLContext context) {
             if (!egl.eglDestroyContext(display, context)) {
-                Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+                Log.e(TAG, "display:" + display + " context: " + context);
                 if (LOG_THREADS) {
-                    Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId());
+                    Log.d(TAG, "tid=" + Thread.currentThread().getId());
                 }
                 EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
             }
@@ -807,8 +832,8 @@
             try {
                 result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
             } catch (IllegalArgumentException e) {
-                // This exception indicates that the surface flinger surface
-                // is not valid. This can happen if the surface flinger surface has
+                // This exception indicates that the surfaceflinger surface
+                // is not valid. This can happen if the surfaceflinger surface has
                 // been torn down, but the application has not yet been
                 // notified via SurfaceHolder.Callback.surfaceDestroyed.
                 // In theory the application should be notified first,
@@ -844,10 +869,11 @@
         EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
     }
 
-    private abstract class BaseConfigChooser
+    private static abstract class BaseConfigChooser
             implements EGLConfigChooser {
-        public BaseConfigChooser(int[] configSpec) {
-            mConfigSpec = filterConfigSpec(configSpec);
+
+        public BaseConfigChooser(int[] configSpec, int version) {
+            mConfigSpec = filterConfigSpec(configSpec, version);
         }
 
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
@@ -881,8 +907,8 @@
 
         protected int[] mConfigSpec;
 
-        private int[] filterConfigSpec(int[] configSpec) {
-            if (mEGLContextClientVersion != 2) {
+        private int[] filterConfigSpec(int[] configSpec, int version) {
+            if (version != 2) {
                 return configSpec;
             }
             /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
@@ -892,7 +918,7 @@
             int[] newConfigSpec = new int[len + 2];
             System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
             newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
-            newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
+            newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;
             newConfigSpec[len+1] = EGL10.EGL_NONE;
             return newConfigSpec;
         }
@@ -902,9 +928,9 @@
      * Choose a configuration with exactly the specified r,g,b,a sizes,
      * and at least the specified depth and stencil sizes.
      */
-    private class ComponentSizeChooser extends BaseConfigChooser {
+    private static class ComponentSizeChooser extends BaseConfigChooser {
         public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
-                int alphaSize, int depthSize, int stencilSize) {
+                int alphaSize, int depthSize, int stencilSize, int version) {
             super(new int[] {
                     EGL10.EGL_RED_SIZE, redSize,
                     EGL10.EGL_GREEN_SIZE, greenSize,
@@ -912,7 +938,7 @@
                     EGL10.EGL_ALPHA_SIZE, alphaSize,
                     EGL10.EGL_DEPTH_SIZE, depthSize,
                     EGL10.EGL_STENCIL_SIZE, stencilSize,
-                    EGL10.EGL_NONE});
+                    EGL10.EGL_NONE}, version);
             mValue = new int[1];
             mRedSize = redSize;
             mGreenSize = greenSize;
@@ -920,7 +946,7 @@
             mAlphaSize = alphaSize;
             mDepthSize = depthSize;
             mStencilSize = stencilSize;
-       }
+        }
 
         @Override
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
@@ -931,14 +957,10 @@
                 int s = findConfigAttrib(egl, display, config,
                         EGL10.EGL_STENCIL_SIZE, 0);
                 if ((d >= mDepthSize) && (s >= mStencilSize)) {
-                    int r = findConfigAttrib(egl, display, config,
-                            EGL10.EGL_RED_SIZE, 0);
-                    int g = findConfigAttrib(egl, display, config,
-                             EGL10.EGL_GREEN_SIZE, 0);
-                    int b = findConfigAttrib(egl, display, config,
-                              EGL10.EGL_BLUE_SIZE, 0);
-                    int a = findConfigAttrib(egl, display, config,
-                            EGL10.EGL_ALPHA_SIZE, 0);
+                    int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
+                    int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
+                    int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
+                    int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
                     if ((r == mRedSize) && (g == mGreenSize)
                             && (b == mBlueSize) && (a == mAlphaSize)) {
                         return config;
@@ -965,16 +987,16 @@
         protected int mAlphaSize;
         protected int mDepthSize;
         protected int mStencilSize;
-        }
+    }
 
     /**
      * This class will choose a RGB_888 surface with
      * or without a depth buffer.
      *
      */
-    private class SimpleEGLConfigChooser extends ComponentSizeChooser {
-        public SimpleEGLConfigChooser(boolean withDepthBuffer) {
-            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
+    private static class SimpleEGLConfigChooser extends ComponentSizeChooser {
+        public SimpleEGLConfigChooser(boolean withDepthBuffer, int version) {
+            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0, version);
         }
     }
 
@@ -991,9 +1013,9 @@
          * Initialize EGL for a given configuration spec.
          * @param configSpec
          */
-        public void start() {
+        public void initialize() {
             if (LOG_EGL) {
-                Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
+                Log.d(TAG, "initialize() tid=" + Thread.currentThread().getId());
             }
             /*
              * Get an EGL instance
@@ -1034,7 +1056,7 @@
                 throwEglException("createContext");
             }
             if (LOG_EGL) {
-                Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
+                Log.d(TAG, "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
             }
 
             mEglSurface = null;
@@ -1048,7 +1070,7 @@
          */
         public boolean createSurface() {
             if (LOG_EGL) {
-                Log.w("EglHelper", "createSurface()  tid=" + Thread.currentThread().getId());
+                Log.d(TAG, "createSurface()  tid=" + Thread.currentThread().getId());
             }
             /*
              * Check preconditions.
@@ -1083,7 +1105,7 @@
             if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
                 int error = mEgl.eglGetError();
                 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
-                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                    Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
                 }
                 return false;
             }
@@ -1097,8 +1119,9 @@
                  * Could not make the context current, probably because the underlying
                  * SurfaceView surface has been destroyed.
                  */
-                logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
-                return false;
+                logEglErrorAsWarning(TAG, "eglMakeCurrent", mEgl.eglGetError());
+                // we fall-through to "true" here because we do have a
+                // valid EGLSurface at this point.
             }
 
             return true;
@@ -1108,8 +1131,7 @@
          * Create a GL object for the current EGL context.
          * @return
          */
-        GL createGL() {
-
+        public GL createGL() {
             GL gl = mEglContext.getGL();
             GLSurfaceView view = mGLSurfaceViewWeakRef.get();
             if (view != null) {
@@ -1145,7 +1167,7 @@
 
         public void destroySurface() {
             if (LOG_EGL) {
-                Log.w("EglHelper", "destroySurface()  tid=" + Thread.currentThread().getId());
+                Log.d(TAG, "destroySurface()  tid=" + Thread.currentThread().getId());
             }
             destroySurfaceImp();
         }
@@ -1163,9 +1185,9 @@
             }
         }
 
-        public void finish() {
+        public void terminate() {
             if (LOG_EGL) {
-                Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId());
+                Log.d(TAG, "terminate() tid=" + Thread.currentThread().getId());
             }
             if (mEglContext != null) {
                 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
@@ -1187,7 +1209,7 @@
         public static void throwEglException(String function, int error) {
             String message = formatEglError(function, error);
             if (LOG_THREADS) {
-                Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " "
+                Log.e(TAG, "throwEglException tid=" + Thread.currentThread().getId() + " "
                         + message);
             }
             throw new RuntimeException(message);
@@ -1207,573 +1229,411 @@
         EGLSurface mEglSurface;
         EGLConfig mEglConfig;
         EGLContext mEglContext;
-
     }
 
     /**
      * A generic GL Thread. Takes care of initializing EGL and GL. Delegates
      * to a Renderer instance to do the actual drawing. Can be configured to
      * render continuously or on request.
-     *
-     * All potentially blocking synchronization is done through the
-     * sGLThreadManager object. This avoids multiple-lock ordering issues.
-     *
      */
-    static class GLThread extends Thread {
-        GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
-            super();
+
+    static class GLThread extends HandlerThread {
+        // only accessed from GLThread
+        private GL10 mGLContext;
+        private int mWidth;
+        private int mHeight;
+        private boolean mSizeChanged;
+        // current render mode
+        private int mRenderMode;
+        // the EGLSurface exists but isn't working for some reason
+        private boolean mEglSurfaceIsBad;
+        // we have an EGLContext
+        private boolean mHaveEglContext;
+        // we have an EGLSurface
+        private boolean mHaveEglSurface;
+        // we have a Surface (i.e.: EGLNativeWindowType)
+        private boolean mHasSurface;
+        // activity is paused
+        private boolean mPaused;
+
+        // constants
+        private EglHelper mEglHelper;
+        private Handler mGLHandler;
+        private Choreographer mChoreographer;
+
+        /*
+         * 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
+         * the GLThread is still alive.
+         */
+        private final WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
+
+        private final Runnable mExecuteDrawAction = new Runnable() {
+            private int mTraceVsyncCounter = 0;
+            @Override
+            public void run() {
+                if (TRACE_ENABLED) {
+                    Trace.traceCounter(Trace.TRACE_TAG_GRAPHICS,
+                            "GLSurfaceView VSYNC counter", (mTraceVsyncCounter++) & 0xf);
+                }
+                executeDraw();
+            }
+        };
+
+        public GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
+            super("GLThread", android.os.Process.THREAD_PRIORITY_DISPLAY);
+            if (LOG_THREADS) {
+                Log.d(TAG, "*** Starting GLThread ***");
+            }
             mWidth = 0;
             mHeight = 0;
-            mRequestRender = true;
             mRenderMode = RENDERMODE_CONTINUOUSLY;
             mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
         }
 
+        private void readyToRun() {
+            mChoreographer = Choreographer.getInstance();
+            mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
+        }
+
+        @Override
+        public void start() {
+            super.start();
+            // getLooper() blocks until the thread is running
+            Looper looper = getLooper();
+            mGLHandler = new Handler(looper);
+            // don't return until the GLThread state has been initialized
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    readyToRun();
+                }
+            }, 0);
+        }
+
         @Override
         public void run() {
-            setName("GLThread " + getId());
-            if (LOG_THREADS) {
-                Log.i("GLThread", "starting tid=" + getId());
-            }
-
             try {
-                guardedRun();
-            } catch (InterruptedException e) {
-                // fall thru and exit normally
+                super.run();
             } finally {
-                sGLThreadManager.threadExiting(this);
+                // by definition the GLThread is not running anymore here
+                stopEglContext();
+                stopEglSurface();
             }
         }
 
-        /*
-         * This private method should only be called inside a
-         * synchronized(sGLThreadManager) block.
-         */
-        private void stopEglSurfaceLocked() {
+        // only call from the GLThread
+        private void stopEglSurface() {
             if (mHaveEglSurface) {
+                if (LOG_SURFACE) {
+                    Log.d(TAG, "releasing EGL surface because paused tid=" + getId());
+                }
                 mHaveEglSurface = false;
                 mEglHelper.destroySurface();
             }
         }
 
-        /*
-         * This private method should only be called inside a
-         * synchronized(sGLThreadManager) block.
-         */
-        private void stopEglContextLocked() {
+        // only call from the GLThread
+        private void stopEglContext() {
             if (mHaveEglContext) {
-                mEglHelper.finish();
+                mEglHelper.terminate();
                 mHaveEglContext = false;
-                sGLThreadManager.releaseEglContextLocked(this);
+                if (LOG_SURFACE) {
+                    Log.d(TAG, "releasing EGL context because paused tid=" + getId());
+                }
             }
         }
-        private void guardedRun() throws InterruptedException {
-            mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
-            mHaveEglContext = false;
-            mHaveEglSurface = false;
-            try {
-                GL10 gl = null;
-                boolean createEglContext = false;
-                boolean createEglSurface = false;
-                boolean createGlInterface = false;
-                boolean lostEglContext = false;
-                boolean sizeChanged = false;
-                boolean wantRenderNotification = false;
-                boolean doRenderNotification = false;
-                boolean askedToReleaseEglContext = false;
-                int w = 0;
-                int h = 0;
-                Runnable event = null;
 
-                while (true) {
-                    synchronized (sGLThreadManager) {
-                        while (true) {
-                            if (mShouldExit) {
-                                return;
-                            }
+        private void updateState() {
+            final boolean wasAbleToDraw = isAbleToDraw();
+            if (!isReadyToDraw()) {
+                return;
+            }
 
-                            if (! mEventQueue.isEmpty()) {
-                                event = mEventQueue.remove(0);
-                                break;
-                            }
+            if (!mHaveEglSurface || mSizeChanged) {
+                // create EGL context if needed
+                boolean reportSurfaceCreated = false;
+                if (!mHaveEglContext) {
+                    mEglHelper.initialize();
+                    mHaveEglContext = true;
+                    reportSurfaceCreated = true;
+                }
 
-                            // Update the pause state.
-                            boolean pausing = false;
-                            if (mPaused != mRequestPaused) {
-                                pausing = mRequestPaused;
-                                mPaused = mRequestPaused;
-                                sGLThreadManager.notifyAll();
-                                if (LOG_PAUSE_RESUME) {
-                                    Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
-                                }
-                            }
+                // get the GL interface for the active EGLContext
+                mGLContext = (GL10)mEglHelper.createGL();
 
-                            // Do we need to give up the EGL context?
-                            if (mShouldReleaseEglContext) {
-                                if (LOG_SURFACE) {
-                                    Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
-                                }
-                                stopEglSurfaceLocked();
-                                stopEglContextLocked();
-                                mShouldReleaseEglContext = false;
-                                askedToReleaseEglContext = true;
-                            }
+                // create EGL Surface
+                mHaveEglSurface = mEglHelper.createSurface();
+                mEglSurfaceIsBad = !mHaveEglSurface;
+                mSizeChanged = false;
 
-                            // Have we lost the EGL context?
-                            if (lostEglContext) {
-                                stopEglSurfaceLocked();
-                                stopEglContextLocked();
-                                lostEglContext = false;
-                            }
-
-                            // When pausing, release the EGL surface:
-                            if (pausing && mHaveEglSurface) {
-                                if (LOG_SURFACE) {
-                                    Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
-                                }
-                                stopEglSurfaceLocked();
-                            }
-
-                            // When pausing, optionally release the EGL Context:
-                            if (pausing && mHaveEglContext) {
-                                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
-                                boolean preserveEglContextOnPause = view == null ?
-                                        false : view.mPreserveEGLContextOnPause;
-                                if (!preserveEglContextOnPause || sGLThreadManager.shouldReleaseEGLContextWhenPausing()) {
-                                    stopEglContextLocked();
-                                    if (LOG_SURFACE) {
-                                        Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
-                                    }
-                                }
-                            }
-
-                            // When pausing, optionally terminate EGL:
-                            if (pausing) {
-                                if (sGLThreadManager.shouldTerminateEGLWhenPausing()) {
-                                    mEglHelper.finish();
-                                    if (LOG_SURFACE) {
-                                        Log.i("GLThread", "terminating EGL because paused tid=" + getId());
-                                    }
-                                }
-                            }
-
-                            // Have we lost the SurfaceView surface?
-                            if ((! mHasSurface) && (! mWaitingForSurface)) {
-                                if (LOG_SURFACE) {
-                                    Log.i("GLThread", "noticed surfaceView surface lost tid=" + getId());
-                                }
-                                if (mHaveEglSurface) {
-                                    stopEglSurfaceLocked();
-                                }
-                                mWaitingForSurface = true;
-                                mSurfaceIsBad = false;
-                                sGLThreadManager.notifyAll();
-                            }
-
-                            // Have we acquired the surface view surface?
-                            if (mHasSurface && mWaitingForSurface) {
-                                if (LOG_SURFACE) {
-                                    Log.i("GLThread", "noticed surfaceView surface acquired tid=" + getId());
-                                }
-                                mWaitingForSurface = false;
-                                sGLThreadManager.notifyAll();
-                            }
-
-                            if (doRenderNotification) {
-                                if (LOG_SURFACE) {
-                                    Log.i("GLThread", "sending render notification tid=" + getId());
-                                }
-                                wantRenderNotification = false;
-                                doRenderNotification = false;
-                                mRenderComplete = true;
-                                sGLThreadManager.notifyAll();
-                            }
-
-                            // Ready to draw?
-                            if (readyToDraw()) {
-
-                                // If we don't have an EGL context, try to acquire one.
-                                if (! mHaveEglContext) {
-                                    if (askedToReleaseEglContext) {
-                                        askedToReleaseEglContext = false;
-                                    } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
-                                        try {
-                                            mEglHelper.start();
-                                        } catch (RuntimeException t) {
-                                            sGLThreadManager.releaseEglContextLocked(this);
-                                            throw t;
-                                        }
-                                        mHaveEglContext = true;
-                                        createEglContext = true;
-
-                                        sGLThreadManager.notifyAll();
-                                    }
-                                }
-
-                                if (mHaveEglContext && !mHaveEglSurface) {
-                                    mHaveEglSurface = true;
-                                    createEglSurface = true;
-                                    createGlInterface = true;
-                                    sizeChanged = true;
-                                }
-
-                                if (mHaveEglSurface) {
-                                    if (mSizeChanged) {
-                                        sizeChanged = true;
-                                        w = mWidth;
-                                        h = mHeight;
-                                        wantRenderNotification = true;
-                                        if (LOG_SURFACE) {
-                                            Log.i("GLThread",
-                                                    "noticing that we want render notification tid="
-                                                    + getId());
-                                        }
-
-                                        // Destroy and recreate the EGL surface.
-                                        createEglSurface = true;
-
-                                        mSizeChanged = false;
-                                    }
-                                    mRequestRender = false;
-                                    sGLThreadManager.notifyAll();
-                                    break;
-                                }
-                            }
-
-                            // By design, this is the only place in a GLThread thread where we wait().
-                            if (LOG_THREADS) {
-                                Log.i("GLThread", "waiting tid=" + getId()
-                                    + " mHaveEglContext: " + mHaveEglContext
-                                    + " mHaveEglSurface: " + mHaveEglSurface
-                                    + " mPaused: " + mPaused
-                                    + " mHasSurface: " + mHasSurface
-                                    + " mSurfaceIsBad: " + mSurfaceIsBad
-                                    + " mWaitingForSurface: " + mWaitingForSurface
-                                    + " mWidth: " + mWidth
-                                    + " mHeight: " + mHeight
-                                    + " mRequestRender: " + mRequestRender
-                                    + " mRenderMode: " + mRenderMode);
-                            }
-                            sGLThreadManager.wait();
-                        }
-                    } // end of synchronized(sGLThreadManager)
-
-                    if (event != null) {
-                        event.run();
-                        event = null;
-                        continue;
-                    }
-
-                    if (createEglSurface) {
-                        if (LOG_SURFACE) {
-                            Log.w("GLThread", "egl createSurface");
-                        }
-                        if (!mEglHelper.createSurface()) {
-                            synchronized(sGLThreadManager) {
-                                mSurfaceIsBad = true;
-                                sGLThreadManager.notifyAll();
-                            }
-                            continue;
-                        }
-                        createEglSurface = false;
-                    }
-
-                    if (createGlInterface) {
-                        gl = (GL10) mEglHelper.createGL();
-
-                        sGLThreadManager.checkGLDriver(gl);
-                        createGlInterface = false;
-                    }
-
-                    if (createEglContext) {
+                // notify use of surface size change
+                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+                if (view != null) {
+                    if (reportSurfaceCreated) {
                         if (LOG_RENDERER) {
-                            Log.w("GLThread", "onSurfaceCreated");
+                            Log.d(TAG, "onSurfaceCreated");
                         }
-                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
-                        if (view != null) {
-                            view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
-                        }
-                        createEglContext = false;
+                        view.mRenderer.onSurfaceCreated(mGLContext, mEglHelper.mEglConfig);
                     }
 
-                    if (sizeChanged) {
-                        if (LOG_RENDERER) {
-                            Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
-                        }
-                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
-                        if (view != null) {
-                            view.mRenderer.onSurfaceChanged(gl, w, h);
-                        }
-                        sizeChanged = false;
+                    if (LOG_RENDERER) {
+                        Log.d(TAG, "onSurfaceChanged(" + mWidth + ", " + mHeight + ")");
                     }
+                    view.mRenderer.onSurfaceChanged(mGLContext, mWidth, mHeight);
+                }
+            }
 
-                    if (LOG_RENDERER_DRAW_FRAME) {
-                        Log.w("GLThread", "onDrawFrame tid=" + getId());
-                    }
-                    {
-                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
-                        if (view != null) {
-                            view.mRenderer.onDrawFrame(gl);
-                        }
-                    }
+            // see if we should kick the rendering loop
+            if (!wasAbleToDraw && isAbleToDraw()) {
+                // we're now able to draw
+                if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
+                    requestRender();
+                }
+            }
+
+            // By design, this is the only place in a GLThread thread where we wait().
+            if (LOG_THREADS) {
+                Log.d(TAG, "waiting tid=" + getId()
+                        + " mHaveEglContext: " + mHaveEglContext
+                        + " mHaveEglSurface: " + mHaveEglSurface
+                        + " mPaused: " + mPaused
+                        + " mHasSurface: " + mHasSurface
+                        + " mSurfaceIsBad: " + mEglSurfaceIsBad
+                        + " mWidth: " + mWidth
+                        + " mHeight: " + mHeight
+                        + " mRenderMode: " + mRenderMode);
+            }
+        }
+
+        private void executeDraw() {
+            if (TRACE_ENABLED) {
+                Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "executeDraw");
+            }
+
+            if (isAbleToDraw()) {
+                if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
+                    requestRender();
+                }
+
+                if (LOG_RENDERER_DRAW_FRAME) {
+                    Log.d(TAG, "onDrawFrame tid=" + getId());
+                }
+
+                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+                if (view != null) {
+                    view.mRenderer.onDrawFrame(mGLContext);
                     int swapError = mEglHelper.swap();
                     switch (swapError) {
                         case EGL10.EGL_SUCCESS:
                             break;
                         case EGL11.EGL_CONTEXT_LOST:
                             if (LOG_SURFACE) {
-                                Log.i("GLThread", "egl context lost tid=" + getId());
+                                Log.d(TAG, "egl context lost tid=" + getId());
                             }
-                            lostEglContext = true;
+                            stopEglSurface();
+                            stopEglContext();
                             break;
                         default:
                             // Other errors typically mean that the current surface is bad,
                             // probably because the SurfaceView surface has been destroyed,
                             // but we haven't been notified yet.
                             // Log the error to help developers understand why rendering stopped.
-                            EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
-
-                            synchronized(sGLThreadManager) {
-                                mSurfaceIsBad = true;
-                                sGLThreadManager.notifyAll();
-                            }
+                            EglHelper.logEglErrorAsWarning(TAG, "eglSwapBuffers", swapError);
+                            mEglSurfaceIsBad = true;
                             break;
                     }
-
-                    if (wantRenderNotification) {
-                        doRenderNotification = true;
-                    }
                 }
+            }
 
-            } finally {
-                /*
-                 * clean-up everything...
-                 */
-                synchronized (sGLThreadManager) {
-                    stopEglSurfaceLocked();
-                    stopEglContextLocked();
+            if (TRACE_ENABLED) {
+                Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+            }
+        }
+
+        private boolean isAbleToDraw() {
+            return mHaveEglContext && mHaveEglSurface && isReadyToDraw();
+        }
+
+        private boolean isReadyToDraw() {
+            return (!mPaused) && mHasSurface && (!mEglSurfaceIsBad)
+                && (mWidth > 0) && (mHeight > 0);
+        }
+
+        private boolean isEglContextReleasedWhenPausing() {
+            GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+            return (view != null) ? !view.mPreserveEGLContextOnPause : false;
+        }
+
+        public void queueEvent(Runnable r) {
+            if (r == null) {
+                throw new IllegalArgumentException("Runnable r must not be null");
+            }
+            mGLHandler.post(r);
+        }
+
+        /*
+         * the call-backs below all run on the GLThread and implement state
+         * changes of the GLSurfaceView and Activity life cycle.
+         */
+
+        private void doSurfaceCreated() {
+            mHasSurface = true;
+            updateState();
+        }
+
+        private void doSurfaceDestroyed() {
+            if (mHasSurface) {
+                if (LOG_SURFACE) {
+                    Log.d(TAG, "noticed surfaceView surface lost tid=" + getId());
+                }
+                stopEglSurface();
+            }
+            mHasSurface = false;
+        }
+
+        private void doPause() {
+            if (mPaused == false) {
+                mPaused = true;
+                stopEglSurface();
+                // When pausing, optionally release the EGL Context:
+                if (mHaveEglContext && isEglContextReleasedWhenPausing()) {
+                    stopEglContext();
                 }
             }
         }
 
-        public boolean ableToDraw() {
-            return mHaveEglContext && mHaveEglSurface && readyToDraw();
-        }
-
-        private boolean readyToDraw() {
-            return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
-                && (mWidth > 0) && (mHeight > 0)
-                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
-        }
-
-        public void setRenderMode(int renderMode) {
-            if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
-                throw new IllegalArgumentException("renderMode");
-            }
-            synchronized(sGLThreadManager) {
-                mRenderMode = renderMode;
-                sGLThreadManager.notifyAll();
+        private void doResume() {
+            mPaused = false;
+            updateState();
+            if (mRenderMode == RENDERMODE_WHEN_DIRTY) {
+                requestRender();
             }
         }
 
-        public int getRenderMode() {
-            synchronized(sGLThreadManager) {
-                return mRenderMode;
-            }
+        private void doWindowResize(final int width, final int height) {
+            // we were not drawing yet. Update the window size and
+            // state and attempt to draw a frame.
+            mSizeChanged = (mWidth != width || mHeight != height);
+            mWidth = width;
+            mHeight = height;
+            updateState();
+            // we always (attempt to) draw a frame before returning
+            executeDraw();
         }
 
-        public void requestRender() {
-            synchronized(sGLThreadManager) {
-                mRequestRender = true;
-                sGLThreadManager.notifyAll();
-            }
+        private void doSetRenderMode(final int renderMode) {
+            mRenderMode = renderMode;
+            requestRender();
         }
 
+        /*
+         * the call-backs below run on the main UI thread, they just
+         * wait while executing work on the GLThread.
+         */
+
         public void surfaceCreated() {
-            synchronized(sGLThreadManager) {
-                if (LOG_THREADS) {
-                    Log.i("GLThread", "surfaceCreated tid=" + getId());
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    doSurfaceCreated();
                 }
-                mHasSurface = true;
-                sGLThreadManager.notifyAll();
-                while((mWaitingForSurface) && (!mExited)) {
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
-            }
+            }, 0);
         }
 
         public void surfaceDestroyed() {
-            synchronized(sGLThreadManager) {
-                if (LOG_THREADS) {
-                    Log.i("GLThread", "surfaceDestroyed tid=" + getId());
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    doSurfaceDestroyed();
                 }
-                mHasSurface = false;
-                sGLThreadManager.notifyAll();
-                while((!mWaitingForSurface) && (!mExited)) {
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
-            }
+            }, 0);
         }
 
         public void onPause() {
-            synchronized (sGLThreadManager) {
-                if (LOG_PAUSE_RESUME) {
-                    Log.i("GLThread", "onPause tid=" + getId());
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    doPause();
                 }
-                mRequestPaused = true;
-                sGLThreadManager.notifyAll();
-                while ((! mExited) && (! mPaused)) {
-                    if (LOG_PAUSE_RESUME) {
-                        Log.i("Main thread", "onPause waiting for mPaused.");
-                    }
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException ex) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
-            }
+            }, 0);
         }
 
         public void onResume() {
-            synchronized (sGLThreadManager) {
-                if (LOG_PAUSE_RESUME) {
-                    Log.i("GLThread", "onResume tid=" + getId());
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    doResume();
                 }
-                mRequestPaused = false;
-                mRequestRender = true;
-                mRenderComplete = false;
-                sGLThreadManager.notifyAll();
-                while ((! mExited) && mPaused && (!mRenderComplete)) {
-                    if (LOG_PAUSE_RESUME) {
-                        Log.i("Main thread", "onResume waiting for !mPaused.");
-                    }
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException ex) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
-            }
+            }, 0);
         }
 
         public void onWindowResize(int w, int h) {
-            synchronized (sGLThreadManager) {
-                mWidth = w;
-                mHeight = h;
-                mSizeChanged = true;
-                mRequestRender = true;
-                mRenderComplete = false;
-                sGLThreadManager.notifyAll();
-
-                // Wait for thread to react to resize and render a frame
-                while (! mExited && !mPaused && !mRenderComplete
-                        && ableToDraw()) {
-                    if (LOG_SURFACE) {
-                        Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId());
-                    }
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException ex) {
-                        Thread.currentThread().interrupt();
-                    }
+            final int width = w;
+            final int height = h;
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    doWindowResize(width, height);
                 }
+            }, 0);
+        }
+
+        /*
+         * the methods below can be called from any thread
+         */
+
+        public void requestRender() {
+            if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
+                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
+                        mExecuteDrawAction, null);
+            } else {
+                /*
+                 * in RENDERMODE_WHEN_DIRTY we schedule the draw callback
+                 * immediately because the developer is manager her
+                 * timing loop manually -- in particular she could be
+                 * using the Choreographer already.
+                 */
+                mGLHandler.post(mExecuteDrawAction);
             }
         }
 
+        public void setRenderMode(final int renderMode) {
+            mGLHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    doSetRenderMode(renderMode);
+                }
+            }, 0);
+        }
+
         public void requestExitAndWait() {
-            // don't call this from GLThread thread or it is a guaranteed
-            // deadlock!
-            synchronized(sGLThreadManager) {
-                mShouldExit = true;
-                sGLThreadManager.notifyAll();
-                while (! mExited) {
-                    try {
-                        sGLThreadManager.wait();
-                    } catch (InterruptedException ex) {
-                        Thread.currentThread().interrupt();
-                    }
-                }
+            getLooper().quit();
+            try {
+                this.join();
+            } catch (InterruptedException e) {
             }
         }
-
-        public void requestReleaseEglContextLocked() {
-            mShouldReleaseEglContext = true;
-            sGLThreadManager.notifyAll();
-        }
-
-        /**
-         * Queue an "event" to be run on the GL rendering thread.
-         * @param r the runnable to be run on the GL rendering thread.
-         */
-        public void queueEvent(Runnable r) {
-            if (r == null) {
-                throw new IllegalArgumentException("r must not be null");
-            }
-            synchronized(sGLThreadManager) {
-                mEventQueue.add(r);
-                sGLThreadManager.notifyAll();
-            }
-        }
-
-        // Once the thread is started, all accesses to the following member
-        // variables are protected by the sGLThreadManager monitor
-        private boolean mShouldExit;
-        private boolean mExited;
-        private boolean mRequestPaused;
-        private boolean mPaused;
-        private boolean mHasSurface;
-        private boolean mSurfaceIsBad;
-        private boolean mWaitingForSurface;
-        private boolean mHaveEglContext;
-        private boolean mHaveEglSurface;
-        private boolean mShouldReleaseEglContext;
-        private int mWidth;
-        private int mHeight;
-        private int mRenderMode;
-        private boolean mRequestRender;
-        private boolean mRenderComplete;
-        private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
-        private boolean mSizeChanged = true;
-
-        // End of member variables protected by the sGLThreadManager monitor.
-
-        private EglHelper mEglHelper;
-
-        /**
-         * 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
-         * the GLThread is still alive.
-         */
-        private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
-
-    }
+    } // class GLThread
 
     static class LogWriter extends Writer {
-
-        @Override public void close() {
+        @Override
+        public void close() {
             flushBuilder();
         }
 
-        @Override public void flush() {
+        @Override
+        public void flush() {
             flushBuilder();
         }
 
-        @Override public void write(char[] buf, int offset, int count) {
-            for(int i = 0; i < count; i++) {
+        @Override
+        public void write(char[] buf, int offset, int count) {
+            for (int i = 0; i < count; i++) {
                 char c = buf[offset + i];
-                if ( c == '\n') {
+                if (c == '\n') {
                     flushBuilder();
-                }
-                else {
+                } else {
                     mBuilder.append(c);
                 }
             }
@@ -1781,7 +1641,7 @@
 
         private void flushBuilder() {
             if (mBuilder.length() > 0) {
-                Log.v("GLSurfaceView", mBuilder.toString());
+                Log.v(TAG, mBuilder.toString());
                 mBuilder.delete(0, mBuilder.length());
             }
         }
@@ -1789,141 +1649,10 @@
         private StringBuilder mBuilder = new StringBuilder();
     }
 
-
     private void checkRenderThreadState() {
         if (mGLThread != null) {
             throw new IllegalStateException(
                     "setRenderer has already been called for this instance.");
         }
     }
-
-    private static class GLThreadManager {
-        private static String TAG = "GLThreadManager";
-
-        public synchronized void threadExiting(GLThread thread) {
-            if (LOG_THREADS) {
-                Log.i("GLThread", "exiting tid=" +  thread.getId());
-            }
-            thread.mExited = true;
-            if (mEglOwner == thread) {
-                mEglOwner = null;
-            }
-            notifyAll();
-        }
-
-        /*
-         * Tries once to acquire the right to use an EGL
-         * context. Does not block. Requires that we are already
-         * in the sGLThreadManager monitor when this is called.
-         *
-         * @return true if the right to use an EGL context was acquired.
-         */
-        public boolean tryAcquireEglContextLocked(GLThread thread) {
-            if (mEglOwner == thread || mEglOwner == null) {
-                mEglOwner = thread;
-                notifyAll();
-                return true;
-            }
-            checkGLESVersion();
-            if (mMultipleGLESContextsAllowed) {
-                return true;
-            }
-            // Notify the owning thread that it should release the context.
-            // TODO: implement a fairness policy. Currently
-            // if the owning thread is drawing continuously it will just
-            // reacquire the EGL context.
-            if (mEglOwner != null) {
-                mEglOwner.requestReleaseEglContextLocked();
-            }
-            return false;
-        }
-
-        /*
-         * Releases the EGL context. Requires that we are already in the
-         * sGLThreadManager monitor when this is called.
-         */
-        public void releaseEglContextLocked(GLThread thread) {
-            if (mEglOwner == thread) {
-                mEglOwner = null;
-            }
-            notifyAll();
-        }
-
-        public synchronized boolean shouldReleaseEGLContextWhenPausing() {
-            // Release the EGL context when pausing even if
-            // the hardware supports multiple EGL contexts.
-            // Otherwise the device could run out of EGL contexts.
-            return mLimitedGLESContexts;
-        }
-
-        public synchronized boolean shouldTerminateEGLWhenPausing() {
-            checkGLESVersion();
-            return !mMultipleGLESContextsAllowed;
-        }
-
-        public synchronized void checkGLDriver(GL10 gl) {
-            if (! mGLESDriverCheckComplete) {
-                checkGLESVersion();
-                String renderer = gl.glGetString(GL10.GL_RENDERER);
-                if (mGLESVersion < kGLES_20) {
-                    mMultipleGLESContextsAllowed =
-                        ! renderer.startsWith(kMSM7K_RENDERER_PREFIX);
-                    notifyAll();
-                }
-                mLimitedGLESContexts = !mMultipleGLESContextsAllowed;
-                if (LOG_SURFACE) {
-                    Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = "
-                        + mMultipleGLESContextsAllowed
-                        + " mLimitedGLESContexts = " + mLimitedGLESContexts);
-                }
-                mGLESDriverCheckComplete = true;
-            }
-        }
-
-        private void checkGLESVersion() {
-            if (! mGLESVersionCheckComplete) {
-                mGLESVersion = SystemProperties.getInt(
-                        "ro.opengles.version",
-                        ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
-                if (mGLESVersion >= kGLES_20) {
-                    mMultipleGLESContextsAllowed = true;
-                }
-                if (LOG_SURFACE) {
-                    Log.w(TAG, "checkGLESVersion mGLESVersion =" +
-                            " " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed);
-                }
-                mGLESVersionCheckComplete = true;
-            }
-        }
-
-        /**
-         * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides
-         * support for hardware-accelerated views, therefore multiple EGL contexts are
-         * supported on all Android 3.0+ EGL drivers.
-         */
-        private boolean mGLESVersionCheckComplete;
-        private int mGLESVersion;
-        private boolean mGLESDriverCheckComplete;
-        private boolean mMultipleGLESContextsAllowed;
-        private boolean mLimitedGLESContexts;
-        private static final int kGLES_20 = 0x20000;
-        private static final String kMSM7K_RENDERER_PREFIX =
-            "Q3Dimension MSM7500 ";
-        private GLThread mEglOwner;
-    }
-
-    private static final GLThreadManager sGLThreadManager = new GLThreadManager();
-
-    private final WeakReference<GLSurfaceView> mThisWeakRef =
-            new WeakReference<GLSurfaceView>(this);
-    private GLThread mGLThread;
-    private Renderer mRenderer;
-    private boolean mDetached;
-    private EGLConfigChooser mEGLConfigChooser;
-    private EGLContextFactory mEGLContextFactory;
-    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
-    private GLWrapper mGLWrapper;
-    private int mDebugFlags;
-    private int mEGLContextClientVersion;
-    private boolean mPreserveEGLContextOnPause;
 }
diff --git a/packages/DefaultContainerService/jni/Android.mk b/packages/DefaultContainerService/jni/Android.mk
index 79ff451..ef4f699 100644
--- a/packages/DefaultContainerService/jni/Android.mk
+++ b/packages/DefaultContainerService/jni/Android.mk
@@ -28,7 +28,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libnativehelper \
-    libutils
+    libutils \
+    liblog
 
 LOCAL_STATIC_LIBRARIES := \
     libdiskusage
@@ -36,4 +37,4 @@
 LOCAL_MODULE := libdefcontainer_jni
 LOCAL_MODULE_TAGS := optional
 
-include $(BUILD_SHARED_LIBRARY)
\ No newline at end of file
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 4a67997..a446e40 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -98,11 +98,11 @@
 
     private void setGpsLocation(String value) {
         UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (! um.isLocationSharingToggleAllowed()) {
+        if (um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
             return;
         }
         final String GPS = LocationManager.GPS_PROVIDER;
-        boolean enabled = 
+        boolean enabled =
                 GPS.equals(value) ||
                 value.startsWith(GPS + ",") ||
                 value.endsWith("," + GPS) ||
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 45319a8..659651b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -322,7 +322,7 @@
     @Override
     public boolean onCreate() {
         mBackupManager = new BackupManager(getContext());
-        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        mUserManager = UserManager.get(getContext());
 
         setAppOps(AppOpsManager.OP_NONE, AppOpsManager.OP_WRITE_SETTINGS);
         establishDbTracking(UserHandle.USER_OWNER);
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml
index fc21df3..b8df88e 100644
--- a/packages/SharedStorageBackup/AndroidManifest.xml
+++ b/packages/SharedStorageBackup/AndroidManifest.xml
@@ -24,5 +24,12 @@
     <application android:allowClearUserData="false"
                  android:permission="android.permission.CONFIRM_FULL_BACKUP"
                  android:backupAgent="SharedStorageAgent" >
+
+        <service android:name=".ObbBackupService"
+                 android:enabled="true"
+                 android:exported="true">
+        </service>
+
     </application>
+
 </manifest>
diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags
index f43cb81..6a66a47 100644
--- a/packages/SharedStorageBackup/proguard.flags
+++ b/packages/SharedStorageBackup/proguard.flags
@@ -1 +1,2 @@
 -keep class com.android.sharedstoragebackup.SharedStorageAgent
+-keep class com.android.sharedstoragebackup.ObbBackupService
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
new file mode 100644
index 0000000..7ebe096
--- /dev/null
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/ObbBackupService.java
@@ -0,0 +1,151 @@
+/*
+ * 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.sharedstoragebackup;
+
+import android.app.Service;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackup;
+import android.app.backup.IBackupManager;
+import android.content.Intent;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.android.internal.backup.IObbBackupService;
+
+/**
+ * Service that the Backup Manager Services delegates OBB backup/restore operations to,
+ * because those require accessing external storage.
+ *
+ * {@hide}
+ */
+public class ObbBackupService extends Service {
+    static final String TAG = "ObbBackupService";
+    static final boolean DEBUG = true;
+
+    /**
+     * IObbBackupService interface implementation
+     */
+    IObbBackupService mService = new IObbBackupService.Stub() {
+        /*
+         * Back up a package's OBB directory tree
+         */
+        @Override
+        public void backupObbs(String packageName, ParcelFileDescriptor data,
+                int token, IBackupManager callbackBinder) {
+            final FileDescriptor outFd = data.getFileDescriptor();
+            try {
+                File obbDir = Environment.getExternalStorageAppObbDirectory(packageName);
+                if (obbDir != null) {
+                    if (obbDir.exists()) {
+                        ArrayList<File> obbList = allFileContents(obbDir);
+                        if (obbList != null) {
+                            // okay, there's at least something there
+                            if (DEBUG) {
+                                Log.i(TAG, obbList.size() + " files to back up");
+                            }
+                            final String rootPath = obbDir.getCanonicalPath();
+                            final BackupDataOutput out = new BackupDataOutput(outFd);
+                            for (File f : obbList) {
+                                final String filePath = f.getCanonicalPath();
+                                if (DEBUG) {
+                                    Log.i(TAG, "storing: " + filePath);
+                                }
+                                FullBackup.backupToTar(packageName, FullBackup.OBB_TREE_TOKEN, null,
+                                        rootPath, filePath, out);
+                            }
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                Log.w(TAG, "Exception backing up OBBs for " + packageName, e);
+            } finally {
+                // Send the EOD marker indicating that there is no more data
+                try {
+                    FileOutputStream out = new FileOutputStream(outFd);
+                    byte[] buf = new byte[4];
+                    out.write(buf);
+                } catch (IOException e) {
+                    Log.e(TAG, "Unable to finalize obb backup stream!");
+                }
+
+                try {
+                    callbackBinder.opComplete(token);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
+        /*
+         * Restore an OBB file for the given package from the incoming stream
+         */
+        @Override
+        public void restoreObbFile(String packageName, ParcelFileDescriptor data,
+                long fileSize, int type, String path, long mode, long mtime,
+                int token, IBackupManager callbackBinder) {
+            try {
+                File outFile = Environment.getExternalStorageAppObbDirectory(packageName);
+                if (outFile != null) {
+                    outFile = new File(outFile, path);
+                }
+                // outFile is null here if we couldn't get access to external storage,
+                // in which case restoreFile() will discard the data cleanly and let
+                // us proceed with the next file segment in the stream.  We pass -1
+                // for the file mode to suppress attempts to chmod() on shared storage.
+                FullBackup.restoreFile(data, fileSize, type, -1, mtime, outFile);
+            } catch (IOException e) {
+                Log.i(TAG, "Exception restoring OBB " + path, e);
+            } finally {
+                try {
+                    callbackBinder.opComplete(token);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
+        ArrayList<File> allFileContents(File rootDir) {
+            final ArrayList<File> files = new ArrayList<File>();
+            final ArrayList<File> dirs = new ArrayList<File>();
+
+            dirs.add(rootDir);
+            while (!dirs.isEmpty()) {
+                File dir = dirs.remove(0);
+                File[] contents = dir.listFiles();
+                if (contents != null) {
+                    for (File f : contents) {
+                        if (f.isDirectory()) dirs.add(f);
+                        else if (f.isFile()) files.add(f);
+                    }
+                }
+            }
+            return files;
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mService.asBinder();
+    }
+}
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index f993ab5..fc4c0f5 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -5,6 +5,8 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
 LOCAL_PACKAGE_NAME := Shell
 LOCAL_CERTIFICATE := platform
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b42db45..ffb4c20 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -68,7 +68,32 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
-    
-    <application android:hasCode="false" android:label="@string/app_label">
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+
+    <application android:label="@string/app_label">
+        <provider
+            android:name="android.support.v4.content.FileProvider"
+            android:authorities="com.android.shell"
+            android:grantUriPermissions="true"
+            android:exported="false">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_provider_paths" />
+        </provider>
+
+        <activity
+            android:name=".BugreportWarningActivity"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true"
+            android:exported="false" />
+
+        <receiver
+            android:name=".BugreportReceiver"
+            android:permission="android.permission.DUMP">
+            <intent-filter>
+                <action android:name="android.intent.action.BUGREPORT_FINISHED" />
+            </intent-filter>
+        </receiver>
     </application>
 </manifest>
diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml
new file mode 100644
index 0000000..dc250d6
--- /dev/null
+++ b/packages/Shell/res/layout/confirm_repeat.xml
@@ -0,0 +1,37 @@
+<?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="wrap_content"
+    android:paddingStart="16dip"
+    android:paddingEnd="16dip"
+    android:paddingTop="8dip"
+    android:paddingBottom="16dip"
+    android:orientation="vertical">
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/bugreport_confirm"
+        android:paddingBottom="16dip"
+        style="?android:attr/textAppearanceMedium" />
+    <CheckBox
+        android:id="@android:id/checkbox"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/bugreport_confirm_repeat" />
+</LinearLayout>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 50610d5..e5606c7 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -16,4 +16,14 @@
 
 <resources>
     <string name="app_label">Shell</string>
+
+    <!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
+    <string name="bugreport_finished_title">Bug report captured</string>
+    <!-- Text of notification indicating that touching will share the captured bugreport. [CHAR LIMIT=100] -->
+    <string name="bugreport_finished_text">Touch to share your bug report</string>
+
+    <!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
+    <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information.  Only share bug reports with apps and people you trust.</string>
+    <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
+    <string name="bugreport_confirm_repeat">Show this message next time</string>
 </resources>
diff --git a/packages/Shell/res/xml/file_provider_paths.xml b/packages/Shell/res/xml/file_provider_paths.xml
new file mode 100644
index 0000000..225c757
--- /dev/null
+++ b/packages/Shell/res/xml/file_provider_paths.xml
@@ -0,0 +1,3 @@
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <files-path name="bugreports" path="bugreports/" />
+</paths>
diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java
new file mode 100644
index 0000000..3748e89
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java
@@ -0,0 +1,45 @@
+/*
+ * 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.shell;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * Preferences related to bug reports.
+ */
+public class BugreportPrefs {
+    private static final String PREFS_BUGREPORT = "bugreports";
+
+    private static final String KEY_WARNING_STATE = "warning-state";
+
+    public static final int STATE_UNKNOWN = 0;
+    public static final int STATE_SHOW = 1;
+    public static final int STATE_HIDE = 2;
+
+    public static int getWarningState(Context context, int def) {
+        final SharedPreferences prefs = context.getSharedPreferences(
+                PREFS_BUGREPORT, Context.MODE_PRIVATE);
+        return prefs.getInt(KEY_WARNING_STATE, def);
+    }
+
+    public static void setWarningState(Context context, int value) {
+        final SharedPreferences prefs = context.getSharedPreferences(
+                PREFS_BUGREPORT, Context.MODE_PRIVATE);
+        prefs.edit().putInt(KEY_WARNING_STATE, value).apply();
+    }
+}
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
new file mode 100644
index 0000000..7a659ee
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -0,0 +1,181 @@
+/*
+ * 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.shell;
+
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.getWarningState;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.support.v4.content.FileProvider;
+import android.text.format.DateUtils;
+import android.util.Patterns;
+
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * Receiver that handles finished bugreports, usually by attaching them to an
+ * {@link Intent#ACTION_SEND}.
+ */
+public class BugreportReceiver extends BroadcastReceiver {
+    private static final String TAG = "Shell";
+
+    private static final String AUTHORITY = "com.android.shell";
+
+    private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
+    private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
+
+    /**
+     * Always keep the newest 8 bugreport files; 4 reports and 4 screenshots are
+     * roughly 17MB of disk space.
+     */
+    private static final int MIN_KEEP_COUNT = 8;
+
+    /**
+     * Always keep bugreports taken in the last week.
+     */
+    private static final long MIN_KEEP_AGE = DateUtils.WEEK_IN_MILLIS;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+        final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+
+        // Files are kept on private storage, so turn into Uris that we can
+        // grant temporary permissions for.
+        final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile);
+        final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile);
+
+        Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
+        Intent notifIntent;
+
+        // Send through warning dialog by default
+        if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
+            notifIntent = buildWarningIntent(context, sendIntent);
+        } else {
+            notifIntent = sendIntent;
+        }
+        notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final Notification.Builder builder = new Notification.Builder(context);
+        builder.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb);
+        builder.setContentTitle(context.getString(R.string.bugreport_finished_title));
+        builder.setTicker(context.getString(R.string.bugreport_finished_title));
+        builder.setContentText(context.getString(R.string.bugreport_finished_text));
+        builder.setContentIntent(PendingIntent.getActivity(
+                context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT));
+        builder.setAutoCancel(true);
+        NotificationManager.from(context).notify(TAG, 0, builder.build());
+
+        // Clean up older bugreports in background
+        final PendingResult result = goAsync();
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                FileUtils.deleteOlderFiles(
+                        bugreportFile.getParentFile(), MIN_KEEP_COUNT, MIN_KEEP_AGE);
+                result.finish();
+                return null;
+            }
+        }.execute();
+    }
+
+    private static Intent buildWarningIntent(Context context, Intent sendIntent) {
+        final Intent intent = new Intent(context, BugreportWarningActivity.class);
+        intent.putExtra(Intent.EXTRA_INTENT, sendIntent);
+        return intent;
+    }
+
+    /**
+     * Build {@link Intent} that can be used to share the given bugreport.
+     */
+    private static Intent buildSendIntent(Context context, Uri bugreportUri, Uri screenshotUri) {
+        final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        intent.setType("application/vnd.android.bugreport");
+
+        intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
+        intent.putExtra(Intent.EXTRA_TEXT, SystemProperties.get("ro.build.description"));
+
+        final ArrayList<Uri> attachments = Lists.newArrayList(bugreportUri, screenshotUri);
+        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
+
+        final Account sendToAccount = findSendToAccount(context);
+        if (sendToAccount != null) {
+            intent.putExtra(Intent.EXTRA_EMAIL, new String[] { sendToAccount.name });
+        }
+
+        return intent;
+    }
+
+    /**
+     * Find the best matching {@link Account} based on build properties.
+     */
+    private static Account findSendToAccount(Context context) {
+        final AccountManager am = (AccountManager) context.getSystemService(
+                Context.ACCOUNT_SERVICE);
+
+        String preferredDomain = SystemProperties.get("sendbug.preferred.domain");
+        if (!preferredDomain.startsWith("@")) {
+            preferredDomain = "@" + preferredDomain;
+        }
+
+        final Account[] accounts = am.getAccounts();
+        Account foundAccount = null;
+        for (Account account : accounts) {
+            if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) {
+                if (!preferredDomain.isEmpty()) {
+                    // if we have a preferred domain and it matches, return; otherwise keep
+                    // looking
+                    if (account.name.endsWith(preferredDomain)) {
+                        return account;
+                    } else {
+                        foundAccount = account;
+                    }
+                    // if we don't have a preferred domain, just return since it looks like
+                    // an email address
+                } else {
+                    return account;
+                }
+            }
+        }
+        return foundAccount;
+    }
+
+    private static File getFileExtra(Intent intent, String key) {
+        final String path = intent.getStringExtra(key);
+        if (path != null) {
+            return new File(path);
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
new file mode 100644
index 0000000..a1d879a
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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.shell;
+
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
+import static com.android.shell.BugreportPrefs.getWarningState;
+import static com.android.shell.BugreportPrefs.setWarningState;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.widget.CheckBox;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+/**
+ * Dialog that warns about contents of a bugreport.
+ */
+public class BugreportWarningActivity extends AlertActivity
+        implements DialogInterface.OnClickListener {
+
+    private Intent mSendIntent;
+    private CheckBox mConfirmRepeat;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mSendIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
+
+        // We need to touch the extras to unpack them so they get migrated to
+        // ClipData correctly.
+        mSendIntent.hasExtra(Intent.EXTRA_STREAM);
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mView = LayoutInflater.from(this).inflate(R.layout.confirm_repeat, null);
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mNegativeButtonText = getString(android.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox);
+        mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) == STATE_SHOW);
+
+        setupAlert();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            // Remember confirm state, and launch target
+            setWarningState(this, mConfirmRepeat.isChecked() ? STATE_SHOW : STATE_HIDE);
+            startActivity(mSendIntent);
+        }
+
+        finish();
+    }
+}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 262000e..015c0cc 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -4,13 +4,10 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../../../ex/carousel/java/com/android/ex/carousel/carousel.rs \
     src/com/android/systemui/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := services telephony-common
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-common-carousel
-
 LOCAL_PACKAGE_NAME := SystemUI
 LOCAL_CERTIFICATE := platform
 
diff --git a/packages/SystemUI/res/layout-land/status_bar_help.xml b/packages/SystemUI/res/layout-land/status_bar_help.xml
index 83b9829..a885b86 100644
--- a/packages/SystemUI/res/layout-land/status_bar_help.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_help.xml
@@ -22,8 +22,8 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/status_bar_cling"
-    android:paddingLeft="40dp"
-    android:paddingRight="40dp"
+    android:paddingStart="40dp"
+    android:paddingEnd="40dp"
     android:background="#DD000000"
     android:focusable="true"
     android:orientation="horizontal" 
@@ -34,7 +34,7 @@
         android:layout_width="wrap_content"
         android:layout_weight="0"
         android:layout_height="wrap_content"
-        android:layout_marginRight="50dp"
+        android:layout_marginEnd="50dp"
         android:gravity="center"
         android:src="@drawable/arrow_dashed"
         tools:ignore="ContentDescription" />
@@ -64,8 +64,8 @@
             style="@style/ClingButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingLeft="50dp"
-            android:paddingRight="50dp"
+            android:paddingStart="50dp"
+            android:paddingEnd="50dp"
             android:text="@android:string/ok" />
     </LinearLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 47d628b..1257641 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -22,8 +22,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="match_parent"
     android:layout_width="wrap_content"
-    android:paddingLeft="@dimen/status_bar_recents_item_padding"
-    android:paddingRight="@dimen/status_bar_recents_item_padding"
+    android:paddingStart="@dimen/status_bar_recents_item_padding"
+    android:paddingEnd="@dimen/status_bar_recents_item_padding"
     android:importantForAccessibility="no"
     android:clipChildren="false">
 
@@ -72,7 +72,7 @@
             android:fadingEdge="horizontal"
             android:fadingEdgeLength="@dimen/status_bar_recents_text_fading_edge_length"
             android:scrollHorizontally="true"
-            android:layout_alignLeft="@id/app_thumbnail"
+            android:layout_alignStart="@id/app_thumbnail"
             android:layout_below="@id/app_thumbnail"
             android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
             android:layout_marginStart="@dimen/status_bar_recents_app_label_left_margin"
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index b51b333..b06166d 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -41,7 +41,8 @@
             android:fadingEdge="horizontal"
             android:scrollbars="none"
             android:layout_gravity="right"
-            android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length">
+            android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
+            android:fitsSystemWindows="true">
 
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
index 96b0a1f..a109191 100644
--- a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
@@ -36,7 +36,7 @@
             android:id="@+id/search_panel_container"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:layout_alignParentRight="true">
+            android:layout_alignParentEnd="true">
 
             <com.android.internal.widget.multiwaveview.GlowPadView
                 android:id="@+id/glow_pad_view"
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 0bac993..47db1c7 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -54,7 +54,7 @@
                 android:layout_weight="1"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_back"
                 systemui:keyCode="4"
@@ -63,7 +63,7 @@
                 android:contentDescription="@string/accessibility_back"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_home"
                 systemui:keyCode="3"
@@ -73,7 +73,7 @@
                 android:contentDescription="@string/accessibility_home"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
                 android:layout_weight="0"
@@ -112,7 +112,7 @@
                 android:layout_weight="1"
                 />
             <ImageView
-                android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:layout_marginStart="40dp"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
@@ -120,14 +120,14 @@
                 android:layout_weight="0"
                 />
             <ImageView
-                android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_lights_out_dot_large"
                 android:scaleType="center"
                 android:layout_weight="0"
                 />
             <ImageView
-                android:layout_width="128dp" android:paddingLeft="25dp" android:paddingRight="25dp"
+                android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
                 android:layout_marginEnd="40dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
@@ -195,7 +195,7 @@
                 android:layout_weight="1"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
-                android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_back"
                 systemui:keyCode="4"
@@ -204,7 +204,7 @@
                 android:contentDescription="@string/accessibility_back"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
-                android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_home"
                 systemui:keyCode="3"
@@ -214,7 +214,7 @@
                 android:contentDescription="@string/accessibility_home"
                 />
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
-                android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_recent"
                 android:layout_weight="0"
@@ -253,7 +253,7 @@
                 android:layout_weight="1"
                 />
             <ImageView
-                android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:layout_marginStart="40dp"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
@@ -261,14 +261,14 @@
                 android:layout_weight="0"
                 />
             <ImageView
-                android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_lights_out_dot_large"
                 android:scaleType="center"
                 android:layout_weight="0"
                 />
             <ImageView
-                android:layout_width="162dp" android:paddingLeft="42dp" android:paddingRight="42dp"
+                android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
                 android:layout_marginEnd="40dp"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_sysbar_lights_out_dot_small"
diff --git a/packages/SystemUI/res/layout/compat_mode_help.xml b/packages/SystemUI/res/layout/compat_mode_help.xml
index c2ed78e..566d07d 100644
--- a/packages/SystemUI/res/layout/compat_mode_help.xml
+++ b/packages/SystemUI/res/layout/compat_mode_help.xml
@@ -52,7 +52,7 @@
         android:background="@drawable/compat_mode_help_divider_bottom"
         android:layout_marginBottom="55dp"
         android:layout_marginEnd="80dp"
-        android:layout_alignLeft="@id/header"
+        android:layout_alignStart="@id/header"
         android:layout_alignParentBottom="true"
         >
         <ImageView
@@ -82,7 +82,7 @@
         android:id="@+id/button"
         android:layout_width="208dp"
         android:layout_height="48dp"
-        android:layout_alignLeft="@id/header"
+        android:layout_alignStart="@id/header"
         android:layout_alignParentBottom="true"
         android:layout_marginBottom="20dp"
         android:textSize="28sp"
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index b547d99..a6f4e9b 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -24,7 +24,7 @@
 	    android:layout_width="wrap_content"
 	    android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:paddingRight="10dp"
+        android:paddingEnd="10dp"
         android:src="@drawable/ic_qs_brightness_auto_off"
         />
     <com.android.systemui.settings.ToggleSlider
@@ -32,7 +32,7 @@
         android:layout_width="0dp"
         android:layout_height="40dp"
         android:layout_weight="1"
-        android:layout_marginRight="2dp"
+        android:layout_marginEnd="2dp"
         android:layout_gravity="center_vertical"
         systemui:text="@string/status_bar_settings_auto_brightness_label"
         />
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 8805175..b27536d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -34,7 +34,7 @@
         android:id="@+id/notification_lights_out"
         android:layout_width="@dimen/status_bar_icon_size"
         android:layout_height="match_parent"
-        android:paddingLeft="6dip"
+        android:paddingStart="6dip"
         android:paddingBottom="2dip"
         android:src="@drawable/ic_sysbar_lights_out_dot_small"
         android:scaleType="center"
@@ -44,8 +44,8 @@
     <LinearLayout android:id="@+id/status_bar_contents"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingLeft="6dip"
-        android:paddingRight="6dip"
+        android:paddingStart="6dip"
+        android:paddingEnd="6dip"
         android:orientation="horizontal"
         >
 
@@ -86,7 +86,7 @@
                 android:id="@+id/signal_battery_cluster"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:paddingLeft="2dp"
+                android:paddingStart="2dp"
                 android:orientation="horizontal"
                 android:gravity="center"
                 >
@@ -99,7 +99,7 @@
                     android:id="@+id/battery"
                     android:layout_height="wrap_content"
                     android:layout_width="wrap_content"
-                    android:paddingLeft="4dip"
+                    android:paddingStart="4dip"
                     />
             </LinearLayout>
     
@@ -109,7 +109,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:singleLine="true"
-                android:paddingLeft="6dip"
+                android:paddingStart="6dip"
                 android:gravity="center_vertical|start"
                 />
         </LinearLayout>
@@ -118,7 +118,7 @@
     <LinearLayout android:id="@+id/ticker"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingLeft="6dip"
+        android:paddingStart="6dip"
         android:animationCache="false"
         android:orientation="horizontal" >
         <ImageSwitcher android:id="@+id/tickerIcon"
@@ -142,7 +142,7 @@
             android:layout_weight="1"
             android:layout_height="wrap_content"
             android:paddingTop="2dip"
-            android:paddingRight="10dip">
+            android:paddingEnd="10dip">
             <TextView
                 android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 54c63f8..9aa7cfd 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -30,8 +30,8 @@
         android:id="@+id/datetime"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
         android:background="@drawable/ic_notify_button_bg"
         android:enabled="false"
         >
diff --git a/packages/SystemUI/res/layout/status_bar_help.xml b/packages/SystemUI/res/layout/status_bar_help.xml
index 3c004ee..f638767 100644
--- a/packages/SystemUI/res/layout/status_bar_help.xml
+++ b/packages/SystemUI/res/layout/status_bar_help.xml
@@ -22,8 +22,8 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/status_bar_cling"
-    android:paddingLeft="40dp"
-    android:paddingRight="40dp"
+    android:paddingStart="40dp"
+    android:paddingEnd="40dp"
     android:background="#DD000000"
     android:focusable="true"
     android:orientation="vertical" 
@@ -56,8 +56,8 @@
         style="@style/ClingButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:paddingLeft="50dp"
-        android:paddingRight="50dp"
+        android:paddingStart="50dp"
+        android:paddingEnd="50dp"
         android:text="@android:string/ok" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 2a93a2b..7a5ff3c 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -20,8 +20,8 @@
         android:gravity="end"
         android:layout_marginEnd="-80dp"
         android:background="@null"
-        android:paddingRight="8dp"
-        android:paddingLeft="8dp"
+        android:paddingEnd="8dp"
+        android:paddingStart="8dp"
         />
 
     <com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index 4bbe277..305aaf2 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -45,7 +45,8 @@
             android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
             android:layout_gravity="bottom|start"
             android:clipToPadding="false"
-            android:clipChildren="false">
+            android:clipChildren="false"
+            android:fitsSystemWindows="true">
 
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index e3cd704..834cc2c 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -36,15 +36,15 @@
         android:layout_toEndOf="@id/toggle"
         android:layout_centerVertical="true"
         android:layout_alignParentEnd="true"
-        android:paddingLeft="20dp"
-        android:paddingRight="20dp"
+        android:paddingStart="20dp"
+        android:paddingEnd="20dp"
         />
     <TextView
         android:id="@+id/label"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_alignLeft="@id/toggle"
-        android:layout_alignRight="@id/toggle"
+        android:layout_alignStart="@id/toggle"
+        android:layout_alignEnd="@id/toggle"
         android:layout_centerVertical="true"
         android:gravity="center"
         android:paddingTop="26dp"
diff --git a/packages/SystemUI/res/layout/system_bar.xml b/packages/SystemUI/res/layout/system_bar.xml
index ac62702..28c9dc0 100644
--- a/packages/SystemUI/res/layout/system_bar.xml
+++ b/packages/SystemUI/res/layout/system_bar.xml
@@ -91,8 +91,8 @@
             <com.android.systemui.statusbar.policy.EventHole android:id="@+id/fake_space_bar"
                 android:layout_height="match_parent"
                 android:layout_width="0dp"
-                android:paddingLeft="8dip"
-                android:paddingRight="8dip"
+                android:paddingStart="8dip"
+                android:paddingEnd="8dip"
                 android:layout_toEndOf="@+id/navigationArea"
                 android:layout_toStartOf="@+id/notificationArea"
                 android:visibility="gone"
diff --git a/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml b/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml
index a33741e..9ad9e05 100644
--- a/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_compat_mode_panel.xml
@@ -22,7 +22,7 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:paddingBottom="@dimen/panel_float"
-    android:paddingRight="20dp"
+    android:paddingEnd="20dp"
     >
     <RadioGroup android:id="@+id/compat_mode_radio_group"
         android:background="@*android:drawable/dialog_full_holo_dark"
diff --git a/packages/SystemUI/res/layout/system_bar_input_methods_item.xml b/packages/SystemUI/res/layout/system_bar_input_methods_item.xml
index 710406c..1a95ec1 100644
--- a/packages/SystemUI/res/layout/system_bar_input_methods_item.xml
+++ b/packages/SystemUI/res/layout/system_bar_input_methods_item.xml
@@ -24,8 +24,8 @@
     android:minHeight="?android:attr/listPreferredItemHeight"
     android:background="@drawable/status_bar_item_background"
     android:orientation="vertical"
-    android:paddingRight="6dip"
-    android:paddingLeft="6dip"
+    android:paddingEnd="6dip"
+    android:paddingStart="6dip"
     android:paddingTop="5dip"
     android:paddingBottom="5dip"
     android:gravity="center_vertical">
@@ -89,8 +89,8 @@
             android:layout_height="match_parent"
             android:layout_marginStart="5dip"
             android:layout_gravity="center_vertical"
-            android:paddingRight="10dip"
-            android:paddingLeft="10dip"
+            android:paddingEnd="10dip"
+            android:paddingStart="10dip"
             android:src="@drawable/ic_sysbar_quicksettings"
             android:visibility="visible"
             android:clickable="true"
diff --git a/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml b/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml
index ecc4f1e..547f937 100644
--- a/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_input_methods_panel.xml
@@ -57,8 +57,8 @@
                         android:minHeight="?android:attr/listPreferredItemHeight"
                         android:background="?android:attr/selectableItemBackground"
                         android:orientation="vertical"
-                        android:paddingRight="6dip"
-                        android:paddingLeft="30dip"
+                        android:paddingEnd="6dip"
+                        android:paddingStart="30dip"
                         android:paddingTop="5dip"
                         android:paddingBottom="5dip"
                         android:gravity="center_vertical"
@@ -103,8 +103,8 @@
                 android:minHeight="?android:attr/listPreferredItemHeight"
                 android:background="?android:attr/selectableItemBackground"
                 android:orientation="vertical"
-                android:paddingRight="6dip"
-                android:paddingLeft="30dip"
+                android:paddingEnd="6dip"
+                android:paddingStart="30dip"
                 android:paddingTop="5dip"
                 android:paddingBottom="5dip"
                 android:gravity="center_vertical"
diff --git a/packages/SystemUI/res/layout/system_bar_notification_area.xml b/packages/SystemUI/res/layout/system_bar_notification_area.xml
index 51ffda7..2fd91ef 100644
--- a/packages/SystemUI/res/layout/system_bar_notification_area.xml
+++ b/packages/SystemUI/res/layout/system_bar_notification_area.xml
@@ -84,7 +84,7 @@
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:singleLine="true"
-            android:paddingLeft="6dip"
+            android:paddingStart="6dip"
             android:layout_marginEnd="8dip"
             android:gravity="center_vertical|start"
             />
@@ -119,14 +119,14 @@
                 android:id="@+id/bluetooth"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
-                android:paddingLeft="4dip"
+                android:paddingStart="4dip"
                 android:visibility="gone"
                 />
             <ImageView
                 android:id="@+id/battery"
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
-                android:paddingLeft="4dip"
+                android:paddingStart="4dip"
                 />
         </LinearLayout>
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml b/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
index 97f774a..d08fbce 100644
--- a/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
@@ -23,9 +23,9 @@
     android:layout_height="wrap_content"
     android:clickable="true"
     android:orientation="vertical"
-    android:paddingLeft="26dp"
+    android:paddingStart="26dp"
     android:paddingTop="14dp"
-    android:paddingRight="26dp"
+    android:paddingEnd="26dp"
     >
 
     <TableLayout
@@ -52,7 +52,7 @@
                     android:id="@+id/bluetooth"
                     android:layout_height="wrap_content"
                     android:layout_width="wrap_content"
-                    android:paddingRight="16dp"
+                    android:paddingEnd="16dp"
                     android:visibility="gone"
                     android:contentDescription="@null"
                     android:layout_gravity="center_vertical"
@@ -65,7 +65,7 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:layout_gravity="center_vertical"
-                android:paddingRight="6dp"
+                android:paddingEnd="6dp"
                 >
 
                 <ImageView
@@ -89,7 +89,7 @@
                 android:layout_gravity="start|center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:paddingRight="12dp"
+                android:paddingEnd="12dp"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:text="@string/status_bar_settings_settings_button"
@@ -101,7 +101,7 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:layout_gravity="center_vertical"
-                android:paddingRight="6dp"
+                android:paddingEnd="6dp"
                 >
 
                 <ImageView
@@ -125,7 +125,7 @@
                 android:layout_gravity="start|center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:paddingRight="12dp"
+                android:paddingEnd="12dp"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:text="@string/status_bar_settings_settings_button"
@@ -138,7 +138,7 @@
                 android:scaleType="centerInside"
                 android:layout_gravity="center_vertical"
                 android:layout_alignBaseline="@id/wifi_signal"
-                android:paddingRight="6dp"
+                android:paddingEnd="6dp"
                 android:contentDescription="@null"
                 />
 
@@ -148,7 +148,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="start|center_vertical"
-                android:paddingRight="2dp"
+                android:paddingEnd="2dp"
                 android:singleLine="true"
                 android:text="@string/status_bar_settings_settings_button"
                 />
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index aed8a8c..3d15d9b 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -49,7 +49,8 @@
             android:fadingEdgeLength="20dip"
             android:layout_gravity="bottom|start"
             android:clipToPadding="false"
-            android:clipChildren="false">
+            android:clipChildren="false"
+            android:fitsSystemWindows="true">
 
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index f3eecf2..627235f 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -627,10 +627,26 @@
             }
             
             mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+            if (mEglContext == EGL_NO_CONTEXT) {
+                throw new RuntimeException("createContext failed " +
+                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+
+            int attribs[] = {
+                EGL_WIDTH, 1,
+                EGL_HEIGHT, 1,
+                EGL_NONE
+            };
+            EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
+            mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext);
 
             int[] maxSize = new int[1];
             Rect frame = surfaceHolder.getSurfaceFrame();
             glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0);
+
+            mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            mEgl.eglDestroySurface(mEglDisplay, tmpSurface);
+
             if(frame.width() > maxSize[0] || frame.height() > maxSize[0]) {
                 mEgl.eglDestroyContext(mEglDisplay, mEglContext);
                 mEgl.eglTerminate(mEglDisplay);
@@ -639,9 +655,8 @@
                     maxSize[0] + "x" + maxSize[0]);
                 return false;
             }
-    
+
             mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
-    
             if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
                 int error = mEgl.eglGetError();
                 if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) {
diff --git a/packages/SystemUI/src/com/android/systemui/UniverseBackground.java b/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
index 7628754..f859880 100644
--- a/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
+++ b/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
@@ -97,7 +97,7 @@
     public UniverseBackground(Context context) {
         super(context);
         setBackgroundColor(0xff000000);
-        mSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
+        mSession = WindowManagerGlobal.getWindowSession();
         mContent = View.inflate(context, R.layout.universe, null);
         addView(mContent);
         mContent.findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
new file mode 100644
index 0000000..2fc7dfc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/FirstFrameAnimatorHelper.java
@@ -0,0 +1,129 @@
+/*
+ * 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.recent;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.Animator.AnimatorListener;
+import android.util.Log;
+import android.view.ViewTreeObserver;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+
+/*
+ *  This is a helper class that listens to updates from the corresponding animation.
+ *  For the first two frames, it adjusts the current play time of the animation to
+ *  prevent jank at the beginning of the animation
+ */
+public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateListener {
+    private static final boolean DEBUG = false;
+    private static final int MAX_DELAY = 1000;
+    private static final int IDEAL_FRAME_DURATION = 16;
+    private View mTarget;
+    private long mStartFrame;
+    private long mStartTime = -1;
+    private boolean mHandlingOnAnimationUpdate;
+    private boolean mAdjustedSecondFrameTime;
+
+    private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
+    private static long sGlobalFrameCounter;
+
+    public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
+        mTarget = target;
+        animator.addUpdateListener(this);
+    }
+
+    public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
+        mTarget = target;
+        vpa.setListener(new AnimatorListenerAdapter() {
+                public void onAnimationStart (Animator animation) {
+                    final ValueAnimator va = (ValueAnimator) animation;
+                    va.addUpdateListener(FirstFrameAnimatorHelper.this);
+                    onAnimationUpdate(va);
+                }
+            });
+    }
+
+    public static void initializeDrawListener(View view) {
+        if (sGlobalDrawListener != null) {
+            view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
+        }
+        sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() {
+                private long mTime = System.currentTimeMillis();
+                public void onDraw() {
+                    sGlobalFrameCounter++;
+                    if (DEBUG) {
+                        long newTime = System.currentTimeMillis();
+                        Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime));
+                        mTime = newTime;
+                    }
+                }
+            };
+        view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
+    }
+
+    public void onAnimationUpdate(final ValueAnimator animation) {
+        final long currentTime = System.currentTimeMillis();
+        if (mStartTime == -1) {
+            mStartFrame = sGlobalFrameCounter;
+            mStartTime = currentTime;
+        }
+
+        if (!mHandlingOnAnimationUpdate) {
+            mHandlingOnAnimationUpdate = true;
+            long frameNum = sGlobalFrameCounter - mStartFrame;
+            // If we haven't drawn our first frame, reset the time to t = 0
+            // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
+            // are no longer in the foreground and no frames are being rendered ever)
+            if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY) {
+                // The first frame on animations doesn't always trigger an invalidate...
+                // force an invalidate here to make sure the animation continues to advance
+                mTarget.getRootView().invalidate();
+                animation.setCurrentPlayTime(0);
+
+            // For the second frame, if the first frame took more than 16ms,
+            // adjust the start time and pretend it took only 16ms anyway. This
+            // prevents a large jump in the animation due to an expensive first frame
+            } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
+                       !mAdjustedSecondFrameTime &&
+                       currentTime > mStartTime + IDEAL_FRAME_DURATION) {
+                animation.setCurrentPlayTime(IDEAL_FRAME_DURATION);
+                mAdjustedSecondFrameTime = true;
+            } else {
+                if (frameNum > 1) {
+                    mTarget.post(new Runnable() {
+                            public void run() {
+                                animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
+                            }
+                        });
+                }
+                if (DEBUG) print(animation);
+            }
+            mHandlingOnAnimationUpdate = false;
+        } else {
+            if (DEBUG) print(animation);
+        }
+    }
+
+    public void print(ValueAnimator animation) {
+        float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
+        Log.d("FirstFrameAnimatorHelper", sGlobalFrameCounter +
+              "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
+              mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index 676326a..c325937 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -177,6 +177,7 @@
         setContentView(R.layout.status_bar_recent_panel);
         mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
         mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
+        mRecentsPanel.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
 
         final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
         recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 3330301..217b7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -256,7 +256,7 @@
             mPerformanceHelper.drawCallback(canvas,
                     left, right, top, bottom, mScrollX, mScrollY,
                     0, 0,
-                    getLeftFadingEdgeStrength(), getRightFadingEdgeStrength());
+                    getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 9c2bca9..32759de 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -45,8 +45,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
@@ -195,50 +194,27 @@
                             oldHolder.calloutLine.setTranslationY(0f);
                         }
                     }
-                    mItemToAnimateInWhenWindowAnimationIsFinished = null;
-
-                    final ViewTreeObserver observer = getViewTreeObserver();
-                    final OnGlobalLayoutListener animateFirstIcon = new OnGlobalLayoutListener() {
-                        public void onGlobalLayout() {
-                            ViewHolder oldHolder = mItemToAnimateInWhenWindowAnimationIsFinished;
-                            if (oldHolder != null) {
-                                oldHolder.iconView.setAlpha(1f);
-                                oldHolder.iconView.setTranslationX(0f);
-                                oldHolder.iconView.setTranslationY(0f);
-                                oldHolder.labelView.setAlpha(1f);
-                                oldHolder.labelView.setTranslationX(0f);
-                                oldHolder.labelView.setTranslationY(0f);
-                                if (oldHolder.calloutLine != null) {
-                                    oldHolder.calloutLine.setAlpha(1f);
-                                    oldHolder.calloutLine.setTranslationX(0f);
-                                    oldHolder.calloutLine.setTranslationY(0f);
-                                }
-                            }
-                            mItemToAnimateInWhenWindowAnimationIsFinished = holder;
-                            int translation = -getResources().getDimensionPixelSize(
-                                    R.dimen.status_bar_recents_app_icon_translate_distance);
-                            final Configuration config = getResources().getConfiguration();
-                            if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
-                                if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-                                    translation = -translation;
-                                }
-                                holder.iconView.setAlpha(0f);
-                                holder.iconView.setTranslationX(translation);
-                                holder.labelView.setAlpha(0f);
-                                holder.labelView.setTranslationX(translation);
-                                holder.calloutLine.setAlpha(0f);
-                                holder.calloutLine.setTranslationX(translation);
-                            } else {
-                                holder.iconView.setAlpha(0f);
-                                holder.iconView.setTranslationY(translation);
-                            }
-                            if (!mWaitingForWindowAnimation) {
-                                animateInIconOfFirstTask();
-                            }
-                            getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                    mItemToAnimateInWhenWindowAnimationIsFinished = holder;
+                    int translation = -getResources().getDimensionPixelSize(
+                            R.dimen.status_bar_recents_app_icon_translate_distance);
+                    final Configuration config = getResources().getConfiguration();
+                    if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+                            translation = -translation;
                         }
-                    };
-                    observer.addOnGlobalLayoutListener(animateFirstIcon);
+                        holder.iconView.setAlpha(0f);
+                        holder.iconView.setTranslationX(translation);
+                        holder.labelView.setAlpha(0f);
+                        holder.labelView.setTranslationX(translation);
+                        holder.calloutLine.setAlpha(0f);
+                        holder.calloutLine.setTranslationX(translation);
+                    } else {
+                        holder.iconView.setAlpha(0f);
+                        holder.iconView.setTranslationY(translation);
+                    }
+                    if (!mWaitingForWindowAnimation) {
+                        animateInIconOfFirstTask();
+                    }
                 }
             }
 
@@ -586,17 +562,20 @@
                 !mRecentTasksLoader.isFirstScreenful()) {
             int timeSinceWindowAnimation =
                     (int) (System.currentTimeMillis() - mWindowAnimationStartTime);
-            final int minStartDelay = 150;
+            final int minStartDelay = 125;
             final int startDelay = Math.max(0, Math.min(
                     minStartDelay - timeSinceWindowAnimation, minStartDelay));
             final int duration = 250;
             final ViewHolder holder = mItemToAnimateInWhenWindowAnimationIsFinished;
             final TimeInterpolator cubic = new DecelerateInterpolator(1.5f);
+            FirstFrameAnimatorHelper.initializeDrawListener(holder.iconView);
             for (View v :
                 new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
                 if (v != null) {
-                    v.animate().translationX(0).translationY(0).alpha(1f).setStartDelay(startDelay)
+                    ViewPropertyAnimator vpa = v.animate().translationX(0).translationY(0)
+                            .alpha(1f).setStartDelay(startDelay)
                             .setDuration(duration).setInterpolator(cubic);
+                    FirstFrameAnimatorHelper h = new FirstFrameAnimatorHelper(vpa, v);
                 }
             }
             mItemToAnimateInWhenWindowAnimationIsFinished = null;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
index 71cc1e4..f17766b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
@@ -38,6 +38,10 @@
     private int mFadingEdgeLength;
     private boolean mIsVertical;
     private boolean mSoftwareRendered = false;
+    private Paint mBlackPaint;
+    private Paint mFadePaint;
+    private Matrix mFadeMatrix;
+    private LinearGradient mFade;
 
     public static RecentsScrollViewPerformanceHelper create(Context context,
             AttributeSet attrs, View scrollView, boolean isVertical) {
@@ -81,18 +85,19 @@
     public void drawCallback(Canvas canvas,
             int left, int right, int top, int bottom, int scrollX, int scrollY,
             float topFadingEdgeStrength, float bottomFadingEdgeStrength,
-            float leftFadingEdgeStrength, float rightFadingEdgeStrength) {
+            float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
 
         if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
                 || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
-            Paint p = new Paint();
-            Matrix matrix = new Matrix();
-            // use use a height of 1, and then wack the matrix each time we
-            // actually use it.
-            Shader fade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
-            // PULL OUT THIS CONSTANT
-
-            p.setShader(fade);
+            if (mFadePaint == null) {
+                mFadePaint = new Paint();
+                mFadeMatrix = new Matrix();
+                // use use a height of 1, and then wack the matrix each time we
+                // actually use it.
+                mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
+                // PULL OUT THIS CONSTANT
+                mFadePaint.setShader(mFade);
+            }
 
             // draw the fade effect
             boolean drawTop = false;
@@ -134,34 +139,41 @@
             }
 
             if (drawTop) {
-                matrix.setScale(1, fadeHeight * topFadeStrength);
-                matrix.postTranslate(left, top);
-                fade.setLocalMatrix(matrix);
-                canvas.drawRect(left, top, right, top + length, p);
+                mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
+                mFadeMatrix.postTranslate(left, top);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(left, top, right, top + length, mFadePaint);
+
+                if (mBlackPaint == null) {
+                    // Draw under the status bar at the top
+                    mBlackPaint = new Paint();
+                    mBlackPaint.setColor(0xFF000000);
+                }
+                canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
             }
 
             if (drawBottom) {
-                matrix.setScale(1, fadeHeight * bottomFadeStrength);
-                matrix.postRotate(180);
-                matrix.postTranslate(left, bottom);
-                fade.setLocalMatrix(matrix);
-                canvas.drawRect(left, bottom - length, right, bottom, p);
+                mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
+                mFadeMatrix.postRotate(180);
+                mFadeMatrix.postTranslate(left, bottom);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
             }
 
             if (drawLeft) {
-                matrix.setScale(1, fadeHeight * leftFadeStrength);
-                matrix.postRotate(-90);
-                matrix.postTranslate(left, top);
-                fade.setLocalMatrix(matrix);
-                canvas.drawRect(left, top, left + length, bottom, p);
+                mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
+                mFadeMatrix.postRotate(-90);
+                mFadeMatrix.postTranslate(left, top);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(left, top, left + length, bottom, mFadePaint);
             }
 
             if (drawRight) {
-                matrix.setScale(1, fadeHeight * rightFadeStrength);
-                matrix.postRotate(90);
-                matrix.postTranslate(right, top);
-                fade.setLocalMatrix(matrix);
-                canvas.drawRect(right - length, top, right, bottom, p);
+                mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
+                mFadeMatrix.postRotate(90);
+                mFadeMatrix.postTranslate(right, top);
+                mFade.setLocalMatrix(mFadeMatrix);
+                canvas.drawRect(right - length, top, right, bottom, mFadePaint);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b3adbaf..403c643f 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -21,6 +21,7 @@
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.FloatMath;
@@ -68,7 +69,7 @@
     }
 
     private int scrollPositionOfMostRecent() {
-        return mLinearLayout.getHeight() - getHeight();
+        return mLinearLayout.getHeight() - getHeight() + mPaddingTop;
     }
 
     private void addToRecycledViews(View v) {
@@ -265,7 +266,7 @@
             mPerformanceHelper.drawCallback(canvas,
                     left, right, top, bottom, mScrollX, mScrollY,
                     getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
-                    0, 0);
+                    0, 0, mPaddingTop);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index b498368..5041617 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -76,11 +76,13 @@
     int result;
 
     void clearImage() {
-        context = null;
         image = null;
         imageUri = null;
         iconSize = 0;
     }
+    void clearContext() {
+        context = null;
+    }
 }
 
 /**
@@ -172,8 +174,6 @@
         mNotificationBuilder.setLargeIcon(croppedIcon);
         // But we still don't set it for the expanded view, allowing the smallIcon to show here.
         mNotificationStyle.bigLargeIcon(null);
-
-        Log.d(TAG, "SaveImageInBackgroundTask constructor");
     }
 
     @Override
@@ -181,7 +181,7 @@
         if (params.length != 1) return null;
         if (isCancelled()) {
             params[0].clearImage();
-            Log.d(TAG, "doInBackground cancelled");
+            params[0].clearContext();
             return null;
         }
 
@@ -246,7 +246,6 @@
             // mounted
             params[0].clearImage();
             params[0].result = 1;
-            Log.d(TAG, "doInBackground failed");
         }
 
         // Recycle the bitmap data
@@ -254,7 +253,6 @@
             image.recycle();
         }
 
-        Log.d(TAG, "doInBackground complete");
         return params[0];
     }
 
@@ -263,7 +261,7 @@
         if (isCancelled()) {
             params.finisher.run();
             params.clearImage();
-            Log.d(TAG, "onPostExecute cancelled");
+            params.clearContext();
             return;
         }
 
@@ -291,7 +289,7 @@
             mNotificationManager.notify(mNotificationId, n);
         }
         params.finisher.run();
-        Log.d(TAG, "onPostExecute complete");
+        params.clearContext();
     }
 }
 
@@ -395,15 +393,12 @@
         // Setup the Camera shutter sound
         mCameraSound = new MediaActionSound();
         mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
-
-        Log.d(TAG, "GlobalScreenshot constructor");
     }
 
     /**
      * Creates a new worker thread and saves the screenshot to the media store.
      */
     private void saveScreenshotInWorkerThread(Runnable finisher) {
-        Log.d(TAG, "saveScreenshotInWorkerThread");
         SaveImageInBackgroundData data = new SaveImageInBackgroundData();
         data.context = mContext;
         data.image = mScreenBitmap;
@@ -411,7 +406,6 @@
         data.finisher = finisher;
         if (mSaveInBgTask != null) {
             mSaveInBgTask.cancel(false);
-            Log.d(TAG, "saveScreenshotInWorkerThread cancel");
         }
         mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager,
                 SCREENSHOT_NOTIFICATION_ID).execute(data);
@@ -436,8 +430,6 @@
      * Takes a screenshot of the current display and shows an animation.
      */
     void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
-        Log.d(TAG, "takeScreenshot");
-
         // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
         // only in the natural orientation of the device :!)
         mDisplay.getRealMetrics(mDisplayMetrics);
@@ -451,8 +443,6 @@
             mDisplayMatrix.mapPoints(dims);
             dims[0] = Math.abs(dims[0]);
             dims[1] = Math.abs(dims[1]);
-
-            Log.d(TAG, "takeScreenshot requiresRotation");
         }
 
         // Take the screenshot
@@ -460,7 +450,6 @@
         if (mScreenBitmap == null) {
             notifyScreenshotError(mContext, mNotificationManager);
             finisher.run();
-            Log.d(TAG, "takeScreenshot null bitmap");
             return;
         }
 
@@ -477,7 +466,6 @@
             // Recycle the previous bitmap
             mScreenBitmap.recycle();
             mScreenBitmap = ss;
-            Log.d(TAG, "takeScreenshot rotation bitmap created");
         }
 
         // Optimizations
@@ -487,7 +475,6 @@
         // Start the post-screenshot animation
         startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
                 statusBarVisible, navBarVisible);
-        Log.d(TAG, "takeScreenshot startedAnimation");
     }
 
 
@@ -496,7 +483,6 @@
      */
     private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,
             boolean navBarVisible) {
-        Log.d(TAG, "startAnimation");
         // Add the view for the animation
         mScreenshotView.setImageBitmap(mScreenBitmap);
         mScreenshotLayout.requestFocus();
@@ -505,11 +491,9 @@
         if (mScreenshotAnimation != null) {
             mScreenshotAnimation.end();
             mScreenshotAnimation.removeAllListeners();
-            Log.d(TAG, "startAnimation reset previous animations");
         }
 
         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
-        Log.d(TAG, "startAnimation layout added to WM");
         ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
         ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
                 statusBarVisible, navBarVisible);
@@ -525,7 +509,6 @@
                 // Clear any references to the bitmap
                 mScreenBitmap = null;
                 mScreenshotView.setImageBitmap(null);
-                Log.d(TAG, "startAnimation onAnimationEnd");
             }
         });
         mScreenshotLayout.post(new Runnable() {
@@ -537,7 +520,6 @@
                 mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                 mScreenshotView.buildLayer();
                 mScreenshotAnimation.start();
-                Log.d(TAG, "startAnimation post runnable");
             }
         });
     }
@@ -675,7 +657,6 @@
     }
 
     static void notifyScreenshotError(Context context, NotificationManager nManager) {
-        Log.d(TAG, "notifyScreenshotError");
         Resources r = context.getResources();
 
         // Clear all existing notification, compose the new notification and show it
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 1954af8..6a0fe47 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -38,15 +38,12 @@
                     final Messenger callback = msg.replyTo;
                     if (mScreenshot == null) {
                         mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
-                        Log.d(TAG, "Global screenshot initialized");
                     }
-                    Log.d(TAG, "Global screenshot captured");
                     mScreenshot.takeScreenshot(new Runnable() {
                         @Override public void run() {
                             Message reply = Message.obtain(null, 1);
                             try {
                                 callback.send(reply);
-                                Log.d(TAG, "Global screenshot completed");
                             } catch (RemoteException e) {
                             }
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7bdcf6e..5b911c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -17,11 +17,11 @@
 
 package com.android.systemui.statusbar;
 
+import android.service.notification.StatusBarNotification;
 import android.content.res.Configuration;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.internal.widget.SizeAdaptiveLayout;
 import com.android.systemui.R;
 import com.android.systemui.SearchPanelView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 752bb0c..cbbaab3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -20,10 +20,10 @@
 import android.os.IBinder;
 import android.os.Message;
 
+import android.service.notification.StatusBarNotification;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
 
 /**
  * This class takes the functions from IStatusBar that come in on
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
old mode 100755
new mode 100644
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c82f250..886ed77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -16,12 +16,11 @@
 
 package com.android.systemui.statusbar;
 
-import android.app.Notification;
+import android.service.notification.StatusBarNotification;
 import android.os.IBinder;
 import android.view.View;
 import android.widget.ImageView;
 
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
 
 import java.util.Comparator;
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 f0b1d7e..c2dc159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -26,6 +26,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
+import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -76,7 +77,6 @@
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -407,6 +407,7 @@
         mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
         mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
+        mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
         mNotificationIcons.setOverflowIndicator(mMoreIcon);
         mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
@@ -707,6 +708,7 @@
 
     private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
         public void onClick(View v) {
+            awakenDreams();
             toggleRecentApps();
         }
     };
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 60e22c5..a7c7fba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -206,8 +206,7 @@
         mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
             @Override
             protected Pair<String, Drawable> doInBackground(Void... params) {
-                final UserManager um =
-                        (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+                final UserManager um = UserManager.get(mContext);
 
                 // Fall back to the UserManager nickname if we can't read the name from the local
                 // profile below.
@@ -292,8 +291,7 @@
             @Override
             public void onClick(View v) {
                 mBar.collapseAllPanels(true);
-                final UserManager um =
-                        (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+                final UserManager um = UserManager.get(mContext);
                 if (um.getUsers(true).size() > 1) {
                     try {
                         WindowManagerGlobal.getWindowManagerService().lockNow(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
index ecc70d6..976dd01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.service.notification.StatusBarNotification;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -23,10 +24,7 @@
 import android.text.StaticLayout;
 import android.text.Layout.Alignment;
 import android.text.TextPaint;
-import android.text.TextUtils;
-import android.util.Slog;
 import android.view.View;
-import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.widget.TextSwitcher;
 import android.widget.TextView;
@@ -35,7 +33,6 @@
 import java.util.ArrayList;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.internal.util.CharSequences;
 
 import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 0944b40..68d048d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -28,16 +28,11 @@
 import android.location.LocationManager;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.util.Slog;
-import android.view.View;
-import android.widget.ImageView;
 
 // private NM API
 import android.app.INotificationManager;
-import com.android.internal.statusbar.StatusBarNotification;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 
 public class LocationController extends BroadcastReceiver {
     private static final String TAG = "StatusBar.LocationController";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 3d6bfe7..05bba89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -23,6 +23,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
+import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -58,7 +59,6 @@
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 0859874..725d9e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -21,9 +21,9 @@
 import android.animation.LayoutTransition;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.service.notification.StatusBarNotification;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -37,11 +37,9 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 413cc78..dc5de02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.tv;
 
+import android.service.notification.StatusBarNotification;
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.statusbar.BaseStatusBar;
 
 import android.os.IBinder;
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
old mode 100755
new mode 100644
index 761eb2d..a2ac8fe
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -102,6 +102,7 @@
     private boolean mIsWaitingForEcmExit = false;
     private boolean mHasTelephony;
     private boolean mHasVibrator;
+    private final boolean mShowSilentToggle;
 
     /**
      * @param context everything needs a context :(
@@ -132,6 +133,9 @@
                 mAirplaneModeObserver);
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = vibrator != null && vibrator.hasVibrator();
+
+        mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useFixedVolume);
     }
 
     /**
@@ -309,7 +313,7 @@
         }
 
         // last: silent mode
-        if (SHOW_SILENT_TOGGLE) {
+        if (mShowSilentToggle) {
             mItems.add(mSilentModeAction);
         }
 
@@ -390,7 +394,7 @@
         mAirplaneModeOn.updateState(mAirplaneState);
         mAdapter.notifyDataSetChanged();
         mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        if (SHOW_SILENT_TOGGLE) {
+        if (mShowSilentToggle) {
             IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
             mContext.registerReceiver(mRingerModeReceiver, filter);
         }
@@ -407,7 +411,7 @@
 
     /** {@inheritDoc} */
     public void onDismiss(DialogInterface dialog) {
-        if (SHOW_SILENT_TOGGLE) {
+        if (mShowSilentToggle) {
             try {
                 mContext.unregisterReceiver(mRingerModeReceiver);
             } catch (IllegalArgumentException ie) {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
new file mode 100644
index 0000000..3cf7e82
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
@@ -0,0 +1,126 @@
+/*
+ *
+ * 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.internal.policy.impl;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Stores a mapping of global keys.
+ * <p>
+ * A global key will NOT go to the foreground application and instead only ever be sent via targeted
+ * broadcast to the specified component. The action of the intent will be
+ * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with
+ * {@link Intent#EXTRA_KEY_EVENT}.
+ */
+final class GlobalKeyManager {
+
+    private static final String TAG = "GlobalKeyManager";
+
+    private static final String TAG_GLOBAL_KEYS = "global_keys";
+    private static final String ATTR_VERSION = "version";
+    private static final String TAG_KEY = "key";
+    private static final String ATTR_KEY_CODE = "keyCode";
+    private static final String ATTR_COMPONENT = "component";
+
+    private static final int GLOBAL_KEY_FILE_VERSION = 1;
+
+    private SparseArray<ComponentName> mKeyMapping;
+
+    public GlobalKeyManager(Context context) {
+        mKeyMapping = new SparseArray<ComponentName>();
+        loadGlobalKeys(context);
+    }
+
+    /**
+     * Broadcasts an intent if the keycode is part of the global key mapping.
+     *
+     * @param context context used to broadcast the event
+     * @param keyCode keyCode which triggered this function
+     * @param event keyEvent which trigged this function
+     * @return {@code true} if this was handled
+     */
+    boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) {
+        if (mKeyMapping.size() > 0) {
+            ComponentName component = mKeyMapping.get(keyCode);
+            if (component != null) {
+                Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
+                        .setComponent(component)
+                        .putExtra(Intent.EXTRA_KEY_EVENT, event);
+                context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the key will be handled globally.
+     */
+    boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) {
+        return mKeyMapping.get(keyCode) != null;
+    }
+
+    private void loadGlobalKeys(Context context) {
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getXml(com.android.internal.R.xml.global_keys);
+            XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS);
+            int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0);
+            if (GLOBAL_KEY_FILE_VERSION == version) {
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (TAG_KEY.equals(element)) {
+                        String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE);
+                        String componentName = parser.getAttributeValue(null, ATTR_COMPONENT);
+                        int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
+                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+                            mKeyMapping.put(keyCode, ComponentName.unflattenFromString(
+                                    componentName));
+                        }
+                    }
+                }
+            }
+        } catch (Resources.NotFoundException e) {
+            Log.w(TAG, "global keys file not found", e);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "XML parser exception reading global keys file", e);
+        } catch (IOException e) {
+            Log.w(TAG, "I/O exception reading global keys file", e);
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 5ad305c..6b28e8e 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -380,6 +380,15 @@
             st.createdPanelView = cb.onCreatePanelView(st.featureId);
         }
 
+        final boolean isActionBarMenu =
+                (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
+
+        if (isActionBarMenu && mActionBar != null) {
+            // Enforce ordering guarantees around events so that the action bar never
+            // dispatches menu-related events before the panel is prepared.
+            mActionBar.setMenuPrepared();
+        }
+
         if (st.createdPanelView == null) {
             // Init the panel state's menu--return false if init failed
             if (st.menu == null || st.refreshMenuContent) {
@@ -389,7 +398,7 @@
                     }
                 }
 
-                if (mActionBar != null) {
+                if (isActionBarMenu && mActionBar != null) {
                     if (mActionMenuPresenterCallback == null) {
                         mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
                     }
@@ -405,7 +414,7 @@
                     // Ditch the menu created above
                     st.setMenu(null);
 
-                    if (mActionBar != null) {
+                    if (isActionBarMenu && mActionBar != null) {
                         // Don't show it in the action bar either
                         mActionBar.setMenu(null, mActionMenuPresenterCallback);
                     }
@@ -430,7 +439,7 @@
             }
 
             if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
-                if (mActionBar != null) {
+                if (isActionBarMenu && mActionBar != null) {
                     // The app didn't want to show the menu for now but it still exists.
                     // Clear it out of the action bar.
                     mActionBar.setMenu(null, mActionMenuPresenterCallback);
@@ -989,6 +998,13 @@
             final Callback cb = getCallback();
             if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
                 if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
+                    // If we have a menu invalidation pending, do it now.
+                    if (mInvalidatePanelMenuPosted &&
+                            (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
+                        mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
+                        mInvalidatePanelMenuRunnable.run();
+                    }
+
                     final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
 
                     // If we don't have a menu or we're waiting for a full content refresh,
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index bb05325..5f9e921 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -59,6 +59,8 @@
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -441,6 +443,9 @@
     PowerManager.WakeLock mBroadcastWakeLock;
     boolean mHavePendingMediaKeyRepeatWithWakeLock;
 
+    // Maps global key codes to the components that will handle them.
+    private GlobalKeyManager mGlobalKeyManager;
+
     // Fallback actions by key code.
     private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
             new SparseArray<KeyCharacterMap.FallbackAction>();
@@ -898,6 +903,8 @@
         mScreenshotChordEnabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableScreenshotChord);
 
+        mGlobalKeyManager = new GlobalKeyManager(mContext);
+
         // Controls rotation and the like.
         initializeHdmiState();
 
@@ -1796,7 +1803,23 @@
                 ? com.android.internal.R.anim.lock_screen_wallpaper_behind_enter
                 : com.android.internal.R.anim.lock_screen_behind_enter);
     }
-    
+
+    private static void awakenDreams() {
+        IDreamManager dreamManager = getDreamManager();
+        if (dreamManager != null) {
+            try {
+                dreamManager.awaken();
+            } catch (RemoteException e) {
+                // fine, stay asleep then
+            }
+        }
+    }
+
+    static IDreamManager getDreamManager() {
+        return IDreamManager.Stub.asInterface(
+                ServiceManager.checkService(DreamService.DREAM_SERVICE));
+    }
+
     static ITelephony getTelephonyService() {
         return ITelephony.Stub.asInterface(
                 ServiceManager.checkService(Context.TELEPHONY_SERVICE));
@@ -2140,6 +2163,10 @@
             return -1;
         }
 
+        if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
+            return -1;
+        }
+
         // Let the application handle the key.
         return 0;
     }
@@ -3585,6 +3612,12 @@
             }
         }
 
+        // If the key would be handled globally, just return the result, don't worry about special
+        // key processing.
+        if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
+            return result;
+        }
+
         // Handle special keys.
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -4535,6 +4568,7 @@
     }
 
     void startDockOrHome() {
+        awakenDreams();
         // We don't have dock home anymore. Home is home. If you lived here, you'd be home by now.
         mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java b/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java
index 6c701c7..34bf6e7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/ClockView.java
@@ -42,7 +42,7 @@
 public class ClockView extends RelativeLayout {
     private static final String ANDROID_CLOCK_FONT_FILE = "/system/fonts/AndroidClock.ttf";
     private final static String M12 = "h:mm";
-    private final static String M24 = "kk:mm";
+    private final static String M24 = "HH:mm";
 
     private Calendar mCalendar;
     private String mFormat;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
index cd7324c..c68bab5 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyButton.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.view.View;
@@ -104,7 +105,8 @@
             Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            getContext().startActivity(intent);
+            getContext().startActivityAsUser(intent,
+                    new UserHandle(mLockPatternUtils.getCurrentUser()));
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java
new file mode 100644
index 0000000..cfe1ef4
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/EmergencyCarrierArea.java
@@ -0,0 +1,62 @@
+/*
+ * 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.internal.policy.impl.keyguard;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+public class EmergencyCarrierArea extends LinearLayout {
+
+    private CarrierText mCarrierText;
+    private EmergencyButton mEmergencyButton;
+
+    public EmergencyCarrierArea(Context context) {
+        super(context);
+    }
+
+    public EmergencyCarrierArea(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mCarrierText = (CarrierText) findViewById(R.id.carrier_text);
+        mEmergencyButton = (EmergencyButton) findViewById(R.id.emergency_call_button);
+
+        // The emergency button overlaps the carrier text, only noticeable when highlighted.
+        // So temporarily hide the carrier text while the emergency button is pressed.
+        mEmergencyButton.setOnTouchListener(new OnTouchListener(){
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                switch(event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        mCarrierText.animate().alpha(0);
+                        break;
+                    case MotionEvent.ACTION_UP:
+                        mCarrierText.animate().alpha(1);
+                        break;
+                }
+                return false;
+            }});
+    }
+}
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 4df434c..965e378 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
@@ -18,17 +18,22 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
 import android.view.View;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 
 import com.android.internal.R;
-
 import com.android.internal.widget.LockPatternUtils;
 
+import java.lang.Math;
+
 public class KeyguardFaceUnlockView extends LinearLayout implements KeyguardSecurityView {
 
     private static final String TAG = "FULKeyguardFaceUnlockView";
@@ -45,6 +50,30 @@
     private boolean mIsShowing = false;
     private final Object mIsShowingLock = new Object();
 
+    private int mLastRotation;
+    private boolean mWatchingRotation;
+    private final IWindowManager mWindowManager =
+            IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+
+    private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
+        public void onRotationChanged(int rotation) {
+            if (DEBUG) Log.d(TAG, "onRotationChanged(): " + mLastRotation + "->" + rotation);
+
+            // If the difference between the new rotation value and the previous rotation value is
+            // equal to 2, the rotation change was 180 degrees.  This stops the biometric unlock
+            // and starts it in the new position.  This is not performed for 90 degree rotations
+            // since a 90 degree rotation is a configuration change, which takes care of this for
+            // us.
+            if (Math.abs(rotation - mLastRotation) == 2) {
+                if (mBiometricUnlock != null) {
+                    mBiometricUnlock.stop();
+                    maybeStartBiometricUnlock();
+                }
+            }
+            mLastRotation = rotation;
+        }
+    };
+
     public KeyguardFaceUnlockView(Context context) {
         this(context, null);
     }
@@ -91,6 +120,14 @@
             mBiometricUnlock.stop();
         }
         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
+        if (mWatchingRotation) {
+            try {
+                mWindowManager.removeRotationWatcher(mRotationWatcher);
+                mWatchingRotation = false;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception when removing rotation watcher");
+            }
+        }
     }
 
     @Override
@@ -100,6 +137,14 @@
             mBiometricUnlock.stop();
         }
         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateCallback);
+        if (mWatchingRotation) {
+            try {
+                mWindowManager.removeRotationWatcher(mRotationWatcher);
+                mWatchingRotation = false;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception when removing rotation watcher");
+            }
+        }
     }
 
     @Override
@@ -108,6 +153,17 @@
         mIsShowing = KeyguardUpdateMonitor.getInstance(mContext).isKeyguardVisible();
         maybeStartBiometricUnlock();
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback);
+
+        // Registers a callback which handles stopping the biometric unlock and restarting it in
+        // the new position for a 180 degree rotation change.
+        if (!mWatchingRotation) {
+            try {
+                mLastRotation = mWindowManager.watchRotation(mRotationWatcher);
+                mWatchingRotation = true;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote exception when adding rotation watcher");
+            }
+        }
     }
 
     @Override
@@ -172,9 +228,15 @@
                 return;
             }
 
-            // TODO: Some of these conditions are handled in KeyguardSecurityModel and may not be
-            // necessary here.
+            // Although these same conditions are handled in KeyguardSecurityModel, they are still
+            // necessary here.  When a tablet is rotated 90 degrees, a configuration change is
+            // triggered and everything is torn down and reconstructed.  That means
+            // KeyguardSecurityModel gets a chance to take care of the logic and doesn't even
+            // reconstruct KeyguardFaceUnlockView if the biometric unlock should be suppressed.
+            // However, for a 180 degree rotation, no configuration change is triggered, so only
+            // the logic here is capable of suppressing Face Unlock.
             if (monitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
+                    && monitor.isAlternateUnlockEnabled()
                     && !monitor.getMaxBiometricUnlockAttemptsReached()
                     && !backupIsTimedOut) {
                 mBiometricUnlock.start();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 06f06b5..4885407 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -35,6 +35,7 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.media.RemoteControlClient;
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -55,6 +56,7 @@
 
 import com.android.internal.R;
 import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.internal.policy.impl.keyguard.KeyguardUpdateMonitor.DisplayClientState;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
@@ -62,9 +64,16 @@
 
 public class KeyguardHostView extends KeyguardViewBase {
     private static final String TAG = "KeyguardHostView";
+    // transport control states
+    static final int TRANSPORT_GONE = 0;
+    static final int TRANSPORT_INVISIBLE = 1;
+    static final int TRANSPORT_VISIBLE = 2;
+
+    private int mTransportState = TRANSPORT_GONE;
 
     // Use this to debug all of keyguard
     public static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    public static boolean DEBUGXPORT = true; // debug music transport control
 
     // Found in KeyguardAppWidgetPickActivity.java
     static final int APPWIDGET_HOST_ID = 0x4B455947;
@@ -109,11 +118,8 @@
 
     private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
 
-    /*package*/ interface TransportCallback {
-        void onListenerDetached();
-        void onListenerAttached();
-        void onPlayStateChanged();
-    }
+    protected int mPlaybackState;
+    protected int mClientGeneration;
 
     /*package*/ interface UserSwitcherCallback {
         void hideSecurityView(int duration);
@@ -141,6 +147,16 @@
         // In other words, mUserId should never change - hence it's marked final.
         mUserId = mLockPatternUtils.getCurrentUser();
 
+        DevicePolicyManager dpm =
+                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        if (dpm != null) {
+            mDisabledFeatures = getDisabledFeatures(dpm);
+            mCameraDisabled = dpm.getCameraDisabled(null);
+        }
+
+        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
+
+        // These need to be created with the user context...
         Context userContext = null;
         try {
             final String packageName = "system";
@@ -153,29 +169,13 @@
             userContext = context;
         }
 
-        // These need to be created with the user context...
         mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
                 Looper.myLooper());
+
+        cleanupAppWidgetIds();
+
         mAppWidgetManager = AppWidgetManager.getInstance(userContext);
 
-        cleanupAppWidgetIds();
-
-        mSecurityModel = new KeyguardSecurityModel(context);
-
-        mViewStateManager = new KeyguardViewStateManager(this);
-
-        DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        if (dpm != null) {
-            mDisabledFeatures = getDisabledFeatures(dpm);
-            mCameraDisabled = dpm.getCameraDisabled(null);
-        }
-
-        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
-
-        cleanupAppWidgetIds();
-
-        mAppWidgetManager = AppWidgetManager.getInstance(mContext);
         mSecurityModel = new KeyguardSecurityModel(context);
 
         mViewStateManager = new KeyguardViewStateManager(this);
@@ -183,6 +183,9 @@
         mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
 
+        // Ensure we have the current state *before* we call showAppropriateWidgetPage()
+        getInitialTransportState();
+
         if (mSafeModeEnabled) {
             Log.v(TAG, "Keyguard widgets disabled by safe mode");
         }
@@ -194,6 +197,14 @@
         }
     }
 
+    private void getInitialTransportState() {
+        DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
+                .getCachedDisplayClientState();
+        mTransportState = (dcs.clearing ? TRANSPORT_GONE :
+            (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
+        mPlaybackState = dcs.playbackState;
+    }
+
     private void cleanupAppWidgetIds() {
         // Since this method may delete a widget (which we can't do until boot completed) we
         // may have to defer it until after boot complete.
@@ -249,8 +260,44 @@
                 mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
             }
         }
+        @Override
+        void onMusicClientIdChanged(
+                int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
+            // Set transport state to invisible until we know music is playing (below)
+            if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
+                Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration);
+            }
+            mClientGeneration = clientGeneration;
+            mTransportState = (clearing ? TRANSPORT_GONE : TRANSPORT_INVISIBLE);
+            KeyguardHostView.this.post(mSwitchPageRunnable);
+        }
+        @Override
+        public void onMusicPlaybackStateChanged(int playbackState, long eventTime) {
+            mPlaybackState = playbackState;
+            if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState);
+            if (mTransportState != TRANSPORT_GONE) {
+                mTransportState = (isMusicPlaying(mPlaybackState) ?
+                        TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE);
+            }
+            KeyguardHostView.this.post(mSwitchPageRunnable);
+        }
     };
 
+    private static final boolean isMusicPlaying(int playbackState) {
+        // This should agree with the list in AudioService.isPlaystateActive()
+        switch (playbackState) {
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private SlidingChallengeLayout mSlidingChallengeLayout;
 
     @Override
@@ -310,9 +357,7 @@
         mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
         mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
 
-        if (!(mContext instanceof Activity)) {
-            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
-        }
+        setBackButtonEnabled(false);
 
         addDefaultWidgets();
 
@@ -329,6 +374,13 @@
         updateSecurityViews();
     }
 
+    private void setBackButtonEnabled(boolean enabled) {
+        if (mContext instanceof Activity) return;  // always enabled in activity mode
+        setSystemUiVisibility(enabled ?
+                getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
+                getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
+    }
+
     private boolean shouldEnableAddWidget() {
         return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
     }
@@ -907,6 +959,10 @@
             // Discard current runnable if we're switching back to the selector view
             setOnDismissAction(null);
         }
+        if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
+            // we're showing account as a backup, provide a way to get back to primary
+            setBackButtonEnabled(true);
+        }
         mCurrentSecuritySelection = securityMode;
     }
 
@@ -1116,10 +1172,8 @@
     }
 
     private void addDefaultWidgets() {
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
-
         if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
             View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
             mAppWidgetContainer.addWidget(addWidget, 0);
             View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
@@ -1145,66 +1199,19 @@
         }
 
         enableUserSelectorIfNecessary();
-        initializeTransportControl();
     }
 
-    private boolean removeTransportFromWidgetPager() {
-        int page = getWidgetPosition(R.id.keyguard_transport_control);
-        if (page != -1) {
-            mAppWidgetContainer.removeWidget(mTransportControl);
-
-            // XXX keep view attached so we still get show/hide events from AudioManager
-            KeyguardHostView.this.addView(mTransportControl);
-            mTransportControl.setVisibility(View.GONE);
-            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
-            return true;
+    /**
+     * Create KeyguardTransportControlView on demand.
+     * @return
+     */
+    private KeyguardTransportControlView getTransportControlView() {
+        if (mTransportControl == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            mTransportControl = (KeyguardTransportControlView)
+                    inflater.inflate(R.layout.keyguard_transport_control_view, this, false);
         }
-        return false;
-    }
-
-    private void addTransportToWidgetPager() {
-        if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
-            KeyguardHostView.this.removeView(mTransportControl);
-            // insert to left of camera if it exists, otherwise after right-most widget
-            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
-            int position = 0; // handle no widget case
-            if (lastWidget >= 0) {
-                position = mAppWidgetContainer.isCameraPage(lastWidget) ?
-                        lastWidget : lastWidget + 1;
-            }
-            mAppWidgetContainer.addWidget(mTransportControl, position);
-            mTransportControl.setVisibility(View.VISIBLE);
-        }
-    }
-
-    private void initializeTransportControl() {
-        mTransportControl =
-            (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
-        mTransportControl.setVisibility(View.GONE);
-
-        // This code manages showing/hiding the transport control. We keep it around and only
-        // add it to the hierarchy if it needs to be present.
-        if (mTransportControl != null) {
-            mTransportControl.setKeyguardCallback(new TransportCallback() {
-                @Override
-                public void onListenerDetached() {
-                    if (removeTransportFromWidgetPager()) {
-                        mTransportControl.post(mSwitchPageRunnable);
-                    }
-                }
-
-                @Override
-                public void onListenerAttached() {
-                    // Transport will be added when playstate changes...
-                    mTransportControl.post(mSwitchPageRunnable);
-                }
-
-                @Override
-                public void onPlayStateChanged() {
-                    mTransportControl.post(mSwitchPageRunnable);
-                }
-            });
-        }
+        return mTransportControl;
     }
 
     private int getInsertPageIndex() {
@@ -1376,7 +1383,7 @@
         if (DEBUG) Log.d(TAG, "onSaveInstanceState");
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        ss.transportState = mViewStateManager.getTransportState();
+        ss.transportState = mTransportState;
         ss.appWidgetToShow = mAppWidgetToShow;
         return ss;
     }
@@ -1390,7 +1397,7 @@
         }
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        mViewStateManager.setTransportState(ss.transportState);
+        mTransportState = (ss.transportState);
         mAppWidgetToShow = ss.appWidgetToShow;
         post(mSwitchPageRunnable);
     }
@@ -1411,19 +1418,33 @@
     }
 
     private void showAppropriateWidgetPage() {
-        int state = mViewStateManager.getTransportState();
-        boolean isMusicPlaying = mTransportControl.isMusicPlaying()
-                || state == KeyguardViewStateManager.TRANSPORT_VISIBLE;
-        if (isMusicPlaying) {
-            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE);
-            addTransportToWidgetPager();
-        } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) {
-            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE);
-        }
-        int pageToShow = getAppropriateWidgetPage(isMusicPlaying);
+        int state = mTransportState;
+        ensureTransportPresentOrRemoved(state);
+        int pageToShow = getAppropriateWidgetPage(state);
         mAppWidgetContainer.setCurrentPage(pageToShow);
     }
 
+    private void ensureTransportPresentOrRemoved(int state) {
+        int page = getWidgetPosition(R.id.keyguard_transport_control);
+        if (state == TRANSPORT_INVISIBLE || state == TRANSPORT_VISIBLE) {
+            if (page == -1) {
+                if (DEBUGXPORT) Log.v(TAG, "add transport");
+                // insert to left of camera if it exists, otherwise after right-most widget
+                int lastWidget = mAppWidgetContainer.getChildCount() - 1;
+                int position = 0; // handle no widget case
+                if (lastWidget >= 0) {
+                    position = mAppWidgetContainer.isCameraPage(lastWidget) ?
+                            lastWidget : lastWidget + 1;
+                }
+                mAppWidgetContainer.addWidget(getTransportControlView(), position);
+            }
+        } else if (page != -1) {
+            if (DEBUGXPORT) Log.v(TAG, "remove transport");
+            mAppWidgetContainer.removeWidget(getTransportControlView());
+            mTransportControl = null;
+        }
+    }
+
     private CameraWidgetFrame findCameraPage() {
         for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
             if (mAppWidgetContainer.isCameraPage(i)) {
@@ -1437,7 +1458,7 @@
         return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
     }
 
-    private int getAppropriateWidgetPage(boolean isMusicPlaying) {
+    private int getAppropriateWidgetPage(int musicTransportState) {
         // assumes at least one widget (besides camera + add)
         if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
             final int childCount = mAppWidgetContainer.getChildCount();
@@ -1450,9 +1471,9 @@
             mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
         }
         // if music playing, show transport
-        if (isMusicPlaying) {
+        if (musicTransportState == TRANSPORT_VISIBLE) {
             if (DEBUG) Log.d(TAG, "Music playing, show transport");
-            return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
+            return mAppWidgetContainer.getWidgetPageIndex(getTransportControlView());
         }
 
         // else show the right-most widget (except for camera)
@@ -1579,6 +1600,12 @@
     }
 
     public boolean handleBackKey() {
+        if (mCurrentSecuritySelection == SecurityMode.Account) {
+            // go back to primary screen and re-disable back
+            setBackButtonEnabled(false);
+            showPrimarySecurityScreen(false /*turningOff*/);
+            return true;
+        }
         if (mCurrentSecuritySelection != SecurityMode.None) {
             mCallback.dismiss(false);
             return true;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index ffa88d5..5e3b7da 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -74,7 +74,6 @@
     private int mCurrentPlayState;
     private AudioManager mAudioManager;
     private IRemoteControlDisplayWeak mIRCD;
-    private boolean mMusicClientPresent = true;
 
     /**
      * The metadata which should be populated into the view once we've been attached
@@ -110,12 +109,6 @@
                 break;
 
             case MSG_SET_GENERATION_ID:
-                if (msg.arg2 != 0) {
-                    // This means nobody is currently registered. Hide the view.
-                    onListenerDetached();
-                } else {
-                    onListenerAttached();
-                }
                 if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
                 mClientGeneration = msg.arg1;
                 mClientIntent = (PendingIntent) msg.obj;
@@ -124,7 +117,6 @@
             }
         }
     };
-    private KeyguardHostView.TransportCallback mTransportCallback;
 
     /**
      * This class is required to have weak linkage to the current TransportControlView
@@ -140,7 +132,8 @@
             mLocalHandler = new WeakReference<Handler>(handler);
         }
 
-        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs) {
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_UPDATE_STATE, generationId, state).sendToTarget();
@@ -154,7 +147,7 @@
             }
         }
 
-        public void setTransportControlFlags(int generationId, int flags) {
+        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
             Handler handler = mLocalHandler.get();
             if (handler != null) {
                 handler.obtainMessage(MSG_SET_TRANSPORT_CONTROLS, generationId, flags)
@@ -195,26 +188,6 @@
         mIRCD = new IRemoteControlDisplayWeak(mHandler);
     }
 
-    protected void onListenerDetached() {
-        mMusicClientPresent = false;
-        if (DEBUG) Log.v(TAG, "onListenerDetached()");
-        if (mTransportCallback != null) {
-            mTransportCallback.onListenerDetached();
-        } else {
-            Log.w(TAG, "onListenerDetached: no callback");
-        }
-    }
-
-    private void onListenerAttached() {
-        mMusicClientPresent = true;
-        if (DEBUG) Log.v(TAG, "onListenerAttached()");
-        if (mTransportCallback != null) {
-            mTransportCallback.onListenerAttached();
-        } else {
-            Log.w(TAG, "onListenerAttached(): no callback");
-        }
-    }
-
     private void updateTransportControls(int transportControlFlags) {
         mTransportControlFlags = transportControlFlags;
     }
@@ -250,6 +223,15 @@
     }
 
     @Override
+    protected void onSizeChanged (int w, int h, int oldw, int oldh) {
+        if (mAttached) {
+            int dim = Math.min(512, Math.max(w, h));
+            if (DEBUG) Log.v(TAG, "TCV uses bitmap size=" + dim);
+            mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
+        }
+    }
+
+    @Override
     public void onDetachedFromWindow() {
         if (DEBUG) Log.v(TAG, "onDetachFromWindow()");
         super.onDetachedFromWindow();
@@ -333,11 +315,6 @@
         updatePlayPauseState(mCurrentPlayState);
     }
 
-    public boolean isMusicPlaying() {
-       return mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING
-               || mCurrentPlayState == RemoteControlClient.PLAYSTATE_BUFFERING;
-    }
-
     private static void setVisibilityBasedOnFlag(View view, int flags, int flag) {
         if ((flags & flag) != 0) {
             view.setVisibility(View.VISIBLE);
@@ -381,7 +358,6 @@
         mBtnPlay.setImageResource(imageResId);
         mBtnPlay.setContentDescription(getResources().getString(imageDescId));
         mCurrentPlayState = state;
-        mTransportCallback.onPlayStateChanged();
     }
 
     static class SavedState extends BaseSavedState {
@@ -414,28 +390,6 @@
         };
     }
 
-    @Override
-    public Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-        ss.clientPresent = mMusicClientPresent;
-        return ss;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-        if (ss.clientPresent) {
-            if (DEBUG) Log.v(TAG, "Reattaching client because it was attached");
-            onListenerAttached();
-        }
-    }
-
     public void onClick(View v) {
         int keyCode = -1;
         if (v == mBtnPrev) {
@@ -513,8 +467,4 @@
                 return false;
         }
     }
-
-    public void setKeyguardCallback(KeyguardHostView.TransportCallback transportCallback) {
-        mTransportCallback = transportCallback;
-    }
 }
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 c9bffbe..159a92d 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -18,12 +18,15 @@
 
 import android.app.ActivityManagerNative;
 import android.app.IUserSwitchObserver;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
+
 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
@@ -32,7 +35,9 @@
 import static android.os.BatteryManager.EXTRA_LEVEL;
 import static android.os.BatteryManager.EXTRA_HEALTH;
 import android.media.AudioManager;
+import android.media.IRemoteControlDisplay;
 import android.os.BatteryManager;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.Message;
@@ -84,6 +89,8 @@
     private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 312;
     protected static final int MSG_BOOT_COMPLETED = 313;
     private static final int MSG_USER_SWITCH_COMPLETE = 314;
+    private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
+    protected static final int MSG_SET_PLAYBACK_STATE = 316;
 
 
     private static KeyguardUpdateMonitor sInstance;
@@ -163,11 +170,67 @@
                 case MSG_BOOT_COMPLETED:
                     handleBootCompleted();
                     break;
-
+                case MSG_SET_CURRENT_CLIENT_ID:
+                    handleSetGenerationId(msg.arg1, msg.arg2 != 0, (PendingIntent) msg.obj);
+                    break;
+                case MSG_SET_PLAYBACK_STATE:
+                    handleSetPlaybackState(msg.arg1, msg.arg2, (Long) msg.obj);
+                    break;
             }
         }
     };
 
+    private AudioManager mAudioManager;
+
+    static class DisplayClientState {
+        public int clientGeneration;
+        public boolean clearing;
+        public PendingIntent intent;
+        public int playbackState;
+        public long playbackEventTime;
+    }
+
+    private DisplayClientState mDisplayClientState = new DisplayClientState();
+
+    /**
+     * This currently implements the bare minimum required to enable showing and hiding
+     * KeyguardTransportControl.  There's a lot of client state to maintain which is why
+     * KeyguardTransportControl maintains an independent connection while it's showing.
+     */
+    private final IRemoteControlDisplay.Stub mRemoteControlDisplay =
+                new IRemoteControlDisplay.Stub() {
+
+        public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) {
+            Message msg = mHandler.obtainMessage(MSG_SET_PLAYBACK_STATE,
+                    generationId, state, stateChangeTimeMs);
+            mHandler.sendMessage(msg);
+        }
+
+        public void setMetadata(int generationId, Bundle metadata) {
+
+        }
+
+        public void setTransportControlInfo(int generationId, int flags, int posCapabilities) {
+
+        }
+
+        public void setArtwork(int generationId, Bitmap bitmap) {
+
+        }
+
+        public void setAllMetadata(int generationId, Bundle metadata, Bitmap bitmap) {
+
+        }
+
+        public void setCurrentClientId(int clientGeneration, PendingIntent mediaIntent,
+                boolean clearing) throws RemoteException {
+            Message msg = mHandler.obtainMessage(MSG_SET_CURRENT_CLIENT_ID,
+                        clientGeneration, (clearing ? 1 : 0), mediaIntent);
+            mHandler.sendMessage(msg);
+        }
+    };
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
 
         public void onReceive(Context context, Intent intent) {
@@ -324,6 +387,32 @@
         return sInstance;
     }
 
+
+    protected void handleSetGenerationId(int clientGeneration, boolean clearing, PendingIntent p) {
+        mDisplayClientState.clientGeneration = clientGeneration;
+        mDisplayClientState.clearing = clearing;
+        mDisplayClientState.intent = p;
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onMusicClientIdChanged(clientGeneration, clearing, p);
+            }
+        }
+    }
+
+    protected void handleSetPlaybackState(int generationId, int playbackState, long eventTime) {
+        if (generationId == mDisplayClientState.clientGeneration) {
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onMusicPlaybackStateChanged(playbackState, eventTime);
+                }
+            }
+        } else {
+            Log.w(TAG, "Ignoring generation id " + generationId + " because it's not current");
+        }
+    }
+
     private KeyguardUpdateMonitor(Context context) {
         mContext = context;
 
@@ -457,6 +546,8 @@
      */
     protected void handleBootCompleted() {
         mBootCompleted = true;
+        mAudioManager = new AudioManager(mContext);
+        mAudioManager.registerRemoteControlDisplay(mRemoteControlDisplay);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -466,7 +557,7 @@
     }
 
     /**
-     * We need to store this state in the KeyguardUpdateMonitor since this class will not be 
+     * We need to store this state in the KeyguardUpdateMonitor since this class will not be
      * destroyed.
      */
     public boolean hasBootCompleted() {
@@ -735,6 +826,12 @@
         callback.onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
         callback.onClockVisibilityChanged();
         callback.onSimStateChanged(mSimState);
+        callback.onMusicClientIdChanged(
+                mDisplayClientState.clientGeneration,
+                mDisplayClientState.clearing,
+                mDisplayClientState.intent);
+        callback.onMusicPlaybackStateChanged(mDisplayClientState.playbackState,
+                mDisplayClientState.playbackEventTime);
     }
 
     public void sendKeyguardVisibilityChanged(boolean showing) {
@@ -838,4 +935,8 @@
                 || simState == IccCardConstants.State.PUK_REQUIRED
                 || simState == IccCardConstants.State.PERM_DISABLED);
     }
+
+    public DisplayClientState getCachedDisplayClientState() {
+        return mDisplayClientState;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
index 2126f06..368ccb3 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitorCallback.java
@@ -15,6 +15,7 @@
  */
 package com.android.internal.policy.impl.keyguard;
 
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.media.AudioManager;
 
@@ -112,4 +113,17 @@
      * KeyguardUpdateMonitor.
      */
     void onBootCompleted() { }
+
+    /**
+     * Called when audio client attaches or detaches from AudioManager.
+     */
+    void onMusicClientIdChanged(int clientGeneration, boolean clearing, PendingIntent intent) { }
+
+    /**
+     * Called when the audio playback state changes.
+     * @param playbackState
+     * @param eventTime
+     */
+    public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
+
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 8562f0c..30c95fb 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -200,6 +200,9 @@
                     stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
             lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
             lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
+            lp.screenOrientation = enableScreenRotation ?
+                    ActivityInfo.SCREEN_ORIENTATION_USER : ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+
             if (ActivityManager.isHighEndGfx()) {
                 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
                 lp.privateFlags |=
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
index 0a166e1..4410063 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -15,7 +15,6 @@
  */
 package com.android.internal.policy.impl.keyguard;
 
-import android.appwidget.AppWidgetManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.view.View;
@@ -35,13 +34,6 @@
     private static final int SCREEN_ON_RING_HINT_DELAY = 300;
     Handler mMainQueue = new Handler(Looper.myLooper());
 
-    // transport control states
-    static final int TRANSPORT_GONE = 0;
-    static final int TRANSPORT_INVISIBLE = 1;
-    static final int TRANSPORT_VISIBLE = 2;
-
-    private int mTransportState = TRANSPORT_GONE;
-
     int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
 
     // Paged view state
@@ -310,14 +302,6 @@
         }
     }
 
-    public void setTransportState(int state) {
-        mTransportState = state;
-    }
-
-    public int getTransportState() {
-        return mTransportState;
-    }
-
     // ChallengeLayout.OnBouncerStateChangedListener
     @Override
     public void onBouncerStateChanged(boolean bouncerActive) {
diff --git a/preloaded-classes b/preloaded-classes
index 10c5c9e..126dd15 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -199,16 +199,14 @@
 android.app.backup.FileBackupHelperBase
 android.app.backup.FullBackup
 android.appwidget.AppWidgetManager
-android.bluetooth.BluetoothAudioGateway
 android.bluetooth.BluetoothSocket
-android.bluetooth.HeadsetBase
 android.bluetooth.IBluetooth
 android.bluetooth.IBluetooth$Stub
 android.bluetooth.IBluetoothA2dp
 android.bluetooth.IBluetoothA2dp$Stub
 android.content.AbstractThreadedSyncAdapter
 android.content.AbstractThreadedSyncAdapter$ISyncAdapterImpl
-undroid.content.AbstractThreadedSyncAdapter$SyncThread
+android.content.AbstractThreadedSyncAdapter$SyncThread
 android.content.BroadcastReceiver
 android.content.BroadcastReceiver$PendingResult
 android.content.ComponentCallbacks
@@ -737,9 +735,6 @@
 android.provider.Settings$Secure
 android.provider.Settings$System
 android.renderscript.RenderScript
-android.server.BluetoothA2dpService
-android.server.BluetoothEventLoop
-android.server.BluetoothService
 android.telephony.PhoneNumberUtils
 android.telephony.TelephonyManager
 android.text.AndroidBidi
@@ -844,7 +839,6 @@
 android.util.FinitePool
 android.util.FloatMath
 android.util.FloatProperty
-android.util.LocaleUtil
 android.util.Log
 android.util.Log$1
 android.util.Log$TerribleFailureHandler
@@ -1022,7 +1016,6 @@
 android.view.ViewRootImpl$InputMethodCallback
 android.view.ViewRootImpl$InvalidateOnAnimationRunnable
 android.view.ViewRootImpl$QueuedInputEvent
-android.view.ViewRootImpl$ResizedInfo
 android.view.ViewRootImpl$RunQueue
 android.view.ViewRootImpl$RunQueue$HandlerAction
 android.view.ViewRootImpl$TrackballAxis
@@ -1042,7 +1035,6 @@
 android.view.ViewTreeObserver$OnTouchModeChangeListener
 android.view.Window
 android.view.Window$Callback
-android.view.Window$LocalWindowManager
 android.view.WindowLeaked
 android.view.WindowManager
 android.view.WindowManager$LayoutParams
@@ -1050,7 +1042,6 @@
 android.view.WindowManagerGlobal
 android.view.WindowManagerGlobal$1
 android.view.WindowManagerImpl
-android.view.WindowManagerImpl$CompatModeWrapper
 android.view.accessibility.AccessibilityEvent
 android.view.accessibility.AccessibilityEventSource
 android.view.accessibility.AccessibilityManager
@@ -1843,7 +1834,6 @@
 java.text.DateFormat
 java.text.DateFormatSymbols
 java.text.DecimalFormat
-java.text.DecimalFormat$1
 java.text.DecimalFormatSymbols
 java.text.FieldPosition
 java.text.Format
@@ -1995,7 +1985,6 @@
 java.util.concurrent.Future
 java.util.concurrent.FutureTask
 java.util.concurrent.FutureTask$WaitNode
-java.util.concurrent.FutureTask$Sync
 java.util.concurrent.LinkedBlockingQueue
 java.util.concurrent.LinkedBlockingQueue$Node
 java.util.concurrent.RejectedExecutionHandler
@@ -2015,7 +2004,6 @@
 java.util.concurrent.atomic.AtomicBoolean
 java.util.concurrent.atomic.AtomicInteger
 java.util.concurrent.atomic.AtomicReference
-java.util.concurrent.atomic.UnsafeAccess
 java.util.concurrent.locks.AbstractOwnableSynchronizer
 java.util.concurrent.locks.AbstractQueuedSynchronizer
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
@@ -2034,7 +2022,6 @@
 java.util.concurrent.locks.ReentrantReadWriteLock$Sync
 java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter
 java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock
-java.util.concurrent.locks.UnsafeAccess
 java.util.jar.Attributes
 java.util.jar.Attributes$Name
 java.util.jar.InitManifest
@@ -2111,7 +2098,6 @@
 javax.net.ssl.X509KeyManager
 javax.net.ssl.X509TrustManager
 javax.security.auth.x500.X500Principal
-libcore.icu.ErrorCode
 libcore.icu.ICU
 libcore.icu.LocaleData
 libcore.icu.NativeBreakIterator
@@ -2122,7 +2108,7 @@
 libcore.icu.NativeIDN
 libcore.icu.NativeNormalizer
 libcore.icu.NativePluralRules
-libcore.icu.TimeZones
+libcore.icu.TimeZoneNames
 libcore.internal.StringPool
 libcore.io.AsynchronousCloseMonitor
 libcore.io.Base64
diff --git a/services/common_time/Android.mk b/services/common_time/Android.mk
index 0606ab4..75eb528 100644
--- a/services/common_time/Android.mk
+++ b/services/common_time/Android.mk
@@ -27,7 +27,8 @@
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libcommon_time_client \
-    libutils
+    libutils \
+    liblog
 
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := common_time
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 159800f..5d913f3 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -29,6 +29,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
+    liblog \
     libandroidfw \
     libutils \
     libhardware \
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 0773afb..376de96 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -40,7 +40,6 @@
 #include <androidfw/KeyCharacterMap.h>
 #include <androidfw/VirtualKeyMap.h>
 
-#include <sha1.h>
 #include <string.h>
 #include <stdint.h>
 #include <dirent.h>
@@ -49,6 +48,7 @@
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
 #include <sys/limits.h>
+#include <sys/sha1.h>
 
 /* this macro is used to tell if "bit" is set in "array"
  * it selects a byte from the array, and does a boolean AND
@@ -162,7 +162,8 @@
         next(NULL),
         fd(fd), id(id), path(path), identifier(identifier),
         classes(0), configuration(NULL), virtualKeyMap(NULL),
-        ffEffectPlaying(false), ffEffectId(-1) {
+        ffEffectPlaying(false), ffEffectId(-1),
+        timestampOverrideSec(0), timestampOverrideUsec(0) {
     memset(keyBitmask, 0, sizeof(keyBitmask));
     memset(absBitmask, 0, sizeof(absBitmask));
     memset(relBitmask, 0, sizeof(relBitmask));
@@ -766,12 +767,37 @@
 
                     size_t count = size_t(readSize) / sizeof(struct input_event);
                     for (size_t i = 0; i < count; i++) {
-                        const struct input_event& iev = readBuffer[i];
-                        ALOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
+                        struct input_event& iev = readBuffer[i];
+                        ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d",
                                 device->path.string(),
                                 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
                                 iev.type, iev.code, iev.value);
 
+                        // Some input devices may have a better concept of the time
+                        // when an input event was actually generated than the kernel
+                        // which simply timestamps all events on entry to evdev.
+                        // This is a custom Android extension of the input protocol
+                        // mainly intended for use with uinput based device drivers.
+                        if (iev.type == EV_MSC) {
+                            if (iev.code == MSC_ANDROID_TIME_SEC) {
+                                device->timestampOverrideSec = iev.value;
+                                continue;
+                            } else if (iev.code == MSC_ANDROID_TIME_USEC) {
+                                device->timestampOverrideUsec = iev.value;
+                                continue;
+                            }
+                        }
+                        if (device->timestampOverrideSec || device->timestampOverrideUsec) {
+                            iev.time.tv_sec = device->timestampOverrideSec;
+                            iev.time.tv_usec = device->timestampOverrideUsec;
+                            if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
+                                device->timestampOverrideSec = 0;
+                                device->timestampOverrideUsec = 0;
+                            }
+                            ALOGV("applied override time %d.%06d",
+                                    int(iev.time.tv_sec), int(iev.time.tv_usec));
+                        }
+
 #ifdef HAVE_POSIX_CLOCKS
                         // Use the time specified in the event instead of the current time
                         // so that downstream code can get more accurate estimates of
@@ -829,8 +855,8 @@
                         event->code = iev.code;
                         event->value = iev.value;
                         event += 1;
+                        capacity -= 1;
                     }
-                    capacity -= count;
                     if (capacity == 0) {
                         // The result buffer is full.  Reset the pending event index
                         // so we will try to read the device again on the next iteration.
@@ -1162,11 +1188,6 @@
             mBuiltInKeyboardId = device->id;
         }
 
-        // 'Q' key support = cheap test of whether this is an alpha-capable kbd
-        if (hasKeycodeLocked(device, AKEYCODE_Q)) {
-            device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
-        }
-
         // See if this device has a DPAD.
         if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
                 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
@@ -1184,6 +1205,14 @@
             }
         }
 
+        // 'Q' key support = cheap test of whether this is an alpha-capable kbd. Many gamepads will
+        // report a broader set of HID usages than they need, however, so we only want to mark this
+        // device as a keyboard if it is not a gamepad.
+        if (hasKeycodeLocked(device, AKEYCODE_Q) &&
+                !(device->classes & INPUT_DEVICE_CLASS_GAMEPAD)) {
+            device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
+        }
+
         // Disable kernel key repeat since we handle it ourselves
         unsigned int repeatRate[] = {0,0};
         if (ioctl(fd, EVIOCSREP, repeatRate)) {
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index afc12ef..c93fc7a 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -42,6 +42,20 @@
 #define BTN_FIRST 0x100  // first button code
 #define BTN_LAST 0x15f   // last button code
 
+/*
+ * These constants are used privately in Android to pass raw timestamps
+ * through evdev from uinput device drivers because there is currently no
+ * other way to transfer this information.  The evdev driver automatically
+ * timestamps all input events with the time they were posted and clobbers
+ * whatever information was passed in.
+ *
+ * For the purposes of this hack, the timestamp is specified in the
+ * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying
+ * seconds and microseconds.
+ */
+#define MSC_ANDROID_TIME_SEC 0x6
+#define MSC_ANDROID_TIME_USEC 0x7
+
 namespace android {
 
 enum {
@@ -329,6 +343,9 @@
         bool ffEffectPlaying;
         int16_t ffEffectId; // initially -1
 
+        int32_t timestampOverrideSec;
+        int32_t timestampOverrideUsec;
+
         Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
         ~Device();
 
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 0465215..23a846b 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -538,7 +538,9 @@
 }
 
 bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
-    return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
+    return keyCode == AKEYCODE_HOME
+            || keyCode == AKEYCODE_ENDCALL
+            || keyCode == AKEYCODE_APP_SWITCH;
 }
 
 bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index d4f932e..430721e 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -165,6 +165,8 @@
  * Input dispatcher configuration.
  *
  * Specifies various options that modify the behavior of the input dispatcher.
+ * The values provided here are merely defaults. The actual values will come from ViewConfiguration
+ * and are passed into the dispatcher during initialization.
  */
 struct InputDispatcherConfiguration {
     // The key repeat initial timeout.
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index bc8df18..ab38ed2 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -882,8 +882,9 @@
                 snprintf(name, sizeof(name), "%d", range.axis);
             }
             dump.appendFormat(INDENT3 "%s: source=0x%08x, "
-                    "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
-                    name, range.source, range.min, range.max, range.flat, range.fuzz);
+                    "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
+                    name, range.source, range.min, range.max, range.flat, range.fuzz,
+                    range.resolution);
         }
     }
 
@@ -2247,20 +2248,20 @@
     if (mParameters.mode == Parameters::MODE_POINTER) {
         float minX, minY, maxX, maxY;
         if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f);
-            info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f);
         }
     } else {
-        info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale);
-        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale);
+        info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
     }
-    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f);
+    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
 
     if (mCursorScrollAccumulator.haveRelativeVWheel()) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
     }
     if (mCursorScrollAccumulator.haveRelativeHWheel()) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
     }
 }
 
@@ -2611,10 +2612,12 @@
         }
 
         if (mCursorScrollAccumulator.haveRelativeVWheel()) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
+                    0.0f);
         }
         if (mCursorScrollAccumulator.haveRelativeHWheel()) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
+                    0.0f);
         }
     }
 }
@@ -2698,6 +2701,12 @@
                 mPointerYZoomScale);
         dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n",
                 mPointerGestureMaxSwipeWidth);
+    } else if (mDeviceMode == DEVICE_MODE_NAVIGATION) {
+        dump.appendFormat(INDENT3 "Navigation Gesture Detector:\n");
+        dump.appendFormat(INDENT4 "AssistStartY: %0.3f\n",
+                mNavigationAssistStartY);
+        dump.appendFormat(INDENT4 "AssistEndY: %0.3f\n",
+                mNavigationAssistEndY);
     }
 }
 
@@ -2788,6 +2797,8 @@
             mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
         } else if (deviceTypeString == "touchPad") {
             mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+        } else if (deviceTypeString == "touchNavigation") {
+            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
         } else if (deviceTypeString == "pointer") {
             mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
         } else if (deviceTypeString != "default") {
@@ -2832,6 +2843,9 @@
     case Parameters::DEVICE_TYPE_TOUCH_PAD:
         dump.append(INDENT4 "DeviceType: touchPad\n");
         break;
+    case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
+        dump.append(INDENT4 "DeviceType: touchNavigation\n");
+        break;
     case Parameters::DEVICE_TYPE_POINTER:
         dump.append(INDENT4 "DeviceType: pointer\n");
         break;
@@ -2885,6 +2899,9 @@
         if (hasStylus()) {
             mSource |= AINPUT_SOURCE_STYLUS;
         }
+    } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
+        mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
+        mDeviceMode = DEVICE_MODE_NAVIGATION;
     } else {
         mSource = AINPUT_SOURCE_TOUCHPAD;
         mDeviceMode = DEVICE_MODE_UNSCALED;
@@ -3055,6 +3072,7 @@
             mOrientedRanges.touchMajor.max = diagonalSize;
             mOrientedRanges.touchMajor.flat = 0;
             mOrientedRanges.touchMajor.fuzz = 0;
+            mOrientedRanges.touchMajor.resolution = 0;
 
             mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
             mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
@@ -3065,6 +3083,7 @@
             mOrientedRanges.toolMajor.max = diagonalSize;
             mOrientedRanges.toolMajor.flat = 0;
             mOrientedRanges.toolMajor.fuzz = 0;
+            mOrientedRanges.toolMajor.resolution = 0;
 
             mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
             mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
@@ -3075,6 +3094,7 @@
             mOrientedRanges.size.max = 1.0;
             mOrientedRanges.size.flat = 0;
             mOrientedRanges.size.fuzz = 0;
+            mOrientedRanges.size.resolution = 0;
         } else {
             mSizeScale = 0.0f;
         }
@@ -3098,6 +3118,7 @@
         mOrientedRanges.pressure.max = 1.0;
         mOrientedRanges.pressure.flat = 0;
         mOrientedRanges.pressure.fuzz = 0;
+        mOrientedRanges.pressure.resolution = 0;
 
         // Tilt
         mTiltXCenter = 0;
@@ -3121,6 +3142,7 @@
             mOrientedRanges.tilt.max = M_PI_2;
             mOrientedRanges.tilt.flat = 0;
             mOrientedRanges.tilt.fuzz = 0;
+            mOrientedRanges.tilt.resolution = 0;
         }
 
         // Orientation
@@ -3134,6 +3156,7 @@
             mOrientedRanges.orientation.max = M_PI;
             mOrientedRanges.orientation.flat = 0;
             mOrientedRanges.orientation.fuzz = 0;
+            mOrientedRanges.orientation.resolution = 0;
         } else if (mCalibration.orientationCalibration !=
                 Calibration::ORIENTATION_CALIBRATION_NONE) {
             if (mCalibration.orientationCalibration
@@ -3157,6 +3180,7 @@
             mOrientedRanges.orientation.max = M_PI_2;
             mOrientedRanges.orientation.flat = 0;
             mOrientedRanges.orientation.fuzz = 0;
+            mOrientedRanges.orientation.resolution = 0;
         }
 
         // Distance
@@ -3182,6 +3206,7 @@
             mOrientedRanges.distance.flat = 0;
             mOrientedRanges.distance.fuzz =
                     mRawPointerAxes.distance.fuzz * mDistanceScale;
+            mOrientedRanges.distance.resolution = 0;
         }
 
         // Compute oriented precision, scales and ranges.
@@ -3196,12 +3221,14 @@
             mOrientedRanges.x.min = mYTranslate;
             mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
             mOrientedRanges.x.flat = 0;
-            mOrientedRanges.x.fuzz = mYScale;
+            mOrientedRanges.x.fuzz = 0;
+            mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
 
             mOrientedRanges.y.min = mXTranslate;
             mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
             mOrientedRanges.y.flat = 0;
-            mOrientedRanges.y.fuzz = mXScale;
+            mOrientedRanges.y.fuzz = 0;
+            mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
             break;
 
         default:
@@ -3211,17 +3238,19 @@
             mOrientedRanges.x.min = mXTranslate;
             mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
             mOrientedRanges.x.flat = 0;
-            mOrientedRanges.x.fuzz = mXScale;
+            mOrientedRanges.x.fuzz = 0;
+            mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
 
             mOrientedRanges.y.min = mYTranslate;
             mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
             mOrientedRanges.y.flat = 0;
-            mOrientedRanges.y.fuzz = mYScale;
+            mOrientedRanges.y.fuzz = 0;
+            mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
             break;
         }
 
-        // Compute pointer gesture detection parameters.
         if (mDeviceMode == DEVICE_MODE_POINTER) {
+            // Compute pointer gesture detection parameters.
             float rawDiagonal = hypotf(rawWidth, rawHeight);
             float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);
 
@@ -3246,10 +3275,14 @@
             // translated into freeform gestures.
             mPointerGestureMaxSwipeWidth =
                     mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
-        }
 
-        // Abort current pointer usages because the state has changed.
-        abortPointerUsage(when, 0 /*policyFlags*/);
+            // Abort current pointer usages because the state has changed.
+            abortPointerUsage(when, 0 /*policyFlags*/);
+        } else if (mDeviceMode == DEVICE_MODE_NAVIGATION) {
+            // Compute navigation parameters.
+            mNavigationAssistStartY = mSurfaceHeight * 0.9f;
+            mNavigationAssistEndY = mSurfaceHeight * 0.5f;
+        }
 
         // Inform the dispatcher about the changes.
         *outResetNeeded = true;
@@ -3588,6 +3621,7 @@
 
     mPointerGesture.reset();
     mPointerSimple.reset();
+    mNavigation.reset();
 
     if (mPointerController != NULL) {
         mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
@@ -3738,6 +3772,8 @@
                 mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords,
                         mCurrentCookedPointerData.idToIndex,
                         mCurrentCookedPointerData.touchingIdBits);
+            } else if (mDeviceMode == DEVICE_MODE_NAVIGATION) {
+                dispatchNavigationAssist(when, policyFlags);
             }
 
             dispatchHoverExit(when, policyFlags);
@@ -5459,6 +5495,44 @@
     dispatchPointerSimple(when, policyFlags, false, false);
 }
 
+void TouchInputMapper::dispatchNavigationAssist(nsecs_t when, uint32_t policyFlags) {
+    if (mCurrentCookedPointerData.touchingIdBits.count() == 1) {
+        if (mLastCookedPointerData.touchingIdBits.isEmpty()) {
+            // First pointer down.
+            uint32_t id = mCurrentCookedPointerData.touchingIdBits.firstMarkedBit();
+            const PointerCoords& coords = mCurrentCookedPointerData.pointerCoordsForId(id);
+            if (coords.getY() >= mNavigationAssistStartY) {
+                // Start tracking the possible assist swipe.
+                mNavigation.activeAssistId = id;
+                return;
+            }
+        } else if (mNavigation.activeAssistId >= 0
+                && mCurrentCookedPointerData.touchingIdBits.hasBit(mNavigation.activeAssistId)) {
+            const PointerCoords& coords = mCurrentCookedPointerData.pointerCoordsForId(
+                    mNavigation.activeAssistId);
+            if (coords.getY() > mNavigationAssistEndY) {
+                // Swipe is still in progress.
+                return;
+            }
+
+            // Detected assist swipe.
+            int32_t metaState = mContext->getGlobalMetaState();
+            NotifyKeyArgs downArgs(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
+                    policyFlags | POLICY_FLAG_VIRTUAL,
+                    AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_ASSIST, 0, metaState, when);
+            getListener()->notifyKey(&downArgs);
+
+            NotifyKeyArgs upArgs(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
+                    policyFlags | POLICY_FLAG_VIRTUAL,
+                    AKEY_EVENT_ACTION_UP, 0, AKEYCODE_ASSIST, 0, metaState, when);
+            getListener()->notifyKey(&upArgs);
+        }
+    }
+
+    // Cancel the assist swipe.
+    mNavigation.activeAssistId = -1;
+}
+
 void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
         int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
         const PointerProperties* properties, const PointerCoords* coords,
@@ -6037,10 +6111,10 @@
     for (size_t i = 0; i < mAxes.size(); i++) {
         const Axis& axis = mAxes.valueAt(i);
         info->addMotionRange(axis.axisInfo.axis, AINPUT_SOURCE_JOYSTICK,
-                axis.min, axis.max, axis.flat, axis.fuzz);
+                axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
             info->addMotionRange(axis.axisInfo.highAxis, AINPUT_SOURCE_JOYSTICK,
-                    axis.min, axis.max, axis.flat, axis.fuzz);
+                    axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
         }
     }
 }
@@ -6070,8 +6144,8 @@
             dump.append(" (invert)");
         }
 
-        dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f\n",
-                axis.min, axis.max, axis.flat, axis.fuzz);
+        dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
+                axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
         dump.appendFormat(INDENT4 "  scale=%0.5f, offset=%0.5f, "
                 "highScale=%0.5f, highOffset=%0.5f\n",
                 axis.scale, axis.offset, axis.highScale, axis.highOffset);
@@ -6117,18 +6191,21 @@
                     float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
                     axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
                             scale, 0.0f, highScale, 0.0f,
-                            0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
+                            0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
+                            rawAxisInfo.resolution * scale);
                 } else if (isCenteredAxis(axisInfo.axis)) {
                     float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
                     float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
                     axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
                             scale, offset, scale, offset,
-                            -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
+                            -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
+                            rawAxisInfo.resolution * scale);
                 } else {
                     float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
                     axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
                             scale, 0.0f, scale, 0.0f,
-                            0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
+                            0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
+                            rawAxisInfo.resolution * scale);
                 }
 
                 // To eliminate noise while the joystick is at rest, filter out small variations
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 61b21e2..312f19b 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -791,6 +791,10 @@
     void clear();
     void copyFrom(const CookedPointerData& other);
 
+    inline const PointerCoords& pointerCoordsForId(uint32_t id) const {
+        return pointerCoords[idToIndex[id]];
+    }
+
     inline bool isHovering(uint32_t pointerIndex) {
         return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id);
     }
@@ -1180,6 +1184,7 @@
         DEVICE_MODE_DISABLED, // input is disabled
         DEVICE_MODE_DIRECT, // direct mapping (touchscreen)
         DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad)
+        DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
         DEVICE_MODE_POINTER, // pointer mapping (pointer)
     };
     DeviceMode mDeviceMode;
@@ -1192,6 +1197,7 @@
         enum DeviceType {
             DEVICE_TYPE_TOUCH_SCREEN,
             DEVICE_TYPE_TOUCH_PAD,
+            DEVICE_TYPE_TOUCH_NAVIGATION,
             DEVICE_TYPE_POINTER,
         };
 
@@ -1431,6 +1437,10 @@
     // The maximum swipe width.
     float mPointerGestureMaxSwipeWidth;
 
+    // The start and end Y thresholds for invoking the assist navigation swipe.
+    float mNavigationAssistStartY;
+    float mNavigationAssistEndY;
+
     struct PointerDistanceHeapElement {
         uint32_t currentPointerIndex : 8;
         uint32_t lastPointerIndex : 8;
@@ -1605,6 +1615,15 @@
         }
     } mPointerSimple;
 
+    struct Navigation {
+        // The id of a pointer that is tracking a possible assist swipe.
+        int32_t activeAssistId; // -1 if none
+
+        void reset() {
+            activeAssistId = -1;
+        }
+    } mNavigation;
+
     // The pointer and scroll velocity controls.
     VelocityControl mPointerVelocityControl;
     VelocityControl mWheelXVelocityControl;
@@ -1640,6 +1659,8 @@
             bool down, bool hovering);
     void abortPointerSimple(nsecs_t when, uint32_t policyFlags);
 
+    void dispatchNavigationAssist(nsecs_t when, uint32_t policyFlags);
+
     // Dispatches a motion event.
     // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
     // method will take care of setting the index and transmuting the action to DOWN or UP
@@ -1729,10 +1750,11 @@
         float highScale;  // scale factor from raw to normalized values of high split
         float highOffset; // offset to add after scaling for normalization of high split
 
-        float min;     // normalized inclusive minimum
-        float max;     // normalized inclusive maximum
-        float flat;    // normalized flat region size
-        float fuzz;    // normalized error tolerance
+        float min;        // normalized inclusive minimum
+        float max;        // normalized inclusive maximum
+        float flat;       // normalized flat region size
+        float fuzz;       // normalized error tolerance
+        float resolution; // normalized resolution in units/mm
 
         float filter;  // filter out small variations of this size
         float currentValue; // current value
@@ -1743,7 +1765,7 @@
         void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
                 bool explicitlyMapped, float scale, float offset,
                 float highScale, float highOffset,
-                float min, float max, float flat, float fuzz) {
+                float min, float max, float flat, float fuzz, float resolution) {
             this->rawAxisInfo = rawAxisInfo;
             this->axisInfo = axisInfo;
             this->explicitlyMapped = explicitlyMapped;
@@ -1755,6 +1777,7 @@
             this->max = max;
             this->flat = flat;
             this->fuzz = fuzz;
+            this->resolution = resolution;
             this->filter = 0;
             resetValue();
         }
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index 8f8c34b..211e64b 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -9,6 +9,7 @@
 
 shared_libraries := \
     libcutils \
+    liblog \
     libandroidfw \
     libutils \
     libhardware \
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 6eea928..fb2828b 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -177,18 +177,20 @@
     // Manages persistent references to RemoteViewsServices from different App Widgets
     private final HashMap<FilterComparison, HashSet<Integer>> mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>();
 
-    Context mContext;
+    final Context mContext;
+    final IPackageManager mPm;
+    final AlarmManager mAlarmManager;
+    final ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
+    final int mUserId;
+    final boolean mHasFeature;
+
     Locale mLocale;
-    IPackageManager mPm;
-    AlarmManager mAlarmManager;
-    ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
     int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
     final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
-    ArrayList<Host> mHosts = new ArrayList<Host>();
+    final ArrayList<Host> mHosts = new ArrayList<Host>();
     // set of package names
-    HashSet<String> mPackagesWithBindWidgetPermission = new HashSet<String>();
+    final HashSet<String> mPackagesWithBindWidgetPermission = new HashSet<String>();
     boolean mSafeMode;
-    int mUserId;
     boolean mStateLoaded;
     int mMaxWidgetBitmapMemory;
 
@@ -204,6 +206,8 @@
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mUserId = userId;
         mSaveStateHandler = saveStateHandler;
+        mHasFeature = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_APP_WIDGETS);
         computeMaximumWidgetBitmapMemory();
     }
 
@@ -426,6 +430,9 @@
 
     private void ensureStateLoadedLocked() {
         if (!mStateLoaded) {
+            if (!mHasFeature) {
+                return;
+            }
             loadAppWidgetListLocked();
             loadStateLocked();
             mStateLoaded = true;
@@ -435,6 +442,9 @@
     public int allocateAppWidgetId(String packageName, int hostId) {
         int callingUid = enforceSystemOrCallingUid(packageName);
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return -1;
+            }
             ensureStateLoadedLocked();
             int appWidgetId = mNextAppWidgetId++;
 
@@ -456,6 +466,9 @@
 
     public void deleteAppWidgetId(int appWidgetId) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
             if (id != null) {
@@ -467,6 +480,9 @@
 
     public void deleteHost(int hostId) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             ensureStateLoadedLocked();
             int callingUid = Binder.getCallingUid();
             Host host = lookupHostLocked(callingUid, hostId);
@@ -479,6 +495,9 @@
 
     public void deleteAllHosts() {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             ensureStateLoadedLocked();
             int callingUid = Binder.getCallingUid();
             final int N = mHosts.size();
@@ -561,6 +580,9 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mAppWidgetIds) {
+                if (!mHasFeature) {
+                    return;
+                }
                 options = cloneIfLocalBinder(options);
                 ensureStateLoadedLocked();
                 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
@@ -622,6 +644,9 @@
 
     public boolean bindAppWidgetIdIfAllowed(
             String packageName, int appWidgetId, ComponentName provider, Bundle options) {
+        if (!mHasFeature) {
+            return false;
+        }
         try {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, null);
         } catch (SecurityException se) {
@@ -649,6 +674,9 @@
     }
 
     public boolean hasBindAppWidgetPermission(String packageName) {
+        if (!mHasFeature) {
+            return false;
+        }
         mContext.enforceCallingPermission(
                 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
                 "hasBindAppWidgetPermission packageName=" + packageName);
@@ -660,6 +688,9 @@
     }
 
     public void setBindAppWidgetPermission(String packageName, boolean permission) {
+        if (!mHasFeature) {
+            return;
+        }
         mContext.enforceCallingPermission(
                 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
                 "setBindAppWidgetPermission packageName=" + packageName);
@@ -678,6 +709,9 @@
     // Binds to a specific RemoteViewsService
     public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
             if (id == null) {
@@ -735,6 +769,9 @@
     // Unbinds from a specific RemoteViewsService
     public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             ensureStateLoadedLocked();
             // Unbind from the RemoteViewsService (which will trigger a callback to the bound
             // RemoteViewsAdapter)
@@ -846,6 +883,9 @@
 
     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return null;
+            }
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
             if (id != null && id.provider != null && !id.provider.zombie) {
@@ -858,6 +898,9 @@
     public RemoteViews getAppWidgetViews(int appWidgetId) {
         if (DBG) log("getAppWidgetViews id=" + appWidgetId);
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return null;
+            }
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
             if (id != null) {
@@ -870,6 +913,9 @@
 
     public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return new ArrayList<AppWidgetProviderInfo>(0);
+            }
             ensureStateLoadedLocked();
             final int N = mInstalledProviders.size();
             ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
@@ -884,6 +930,9 @@
     }
 
     public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
+        if (!mHasFeature) {
+            return;
+        }
         if (appWidgetIds == null) {
             return;
         }
@@ -929,6 +978,9 @@
 
     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             options = cloneIfLocalBinder(options);
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
@@ -953,6 +1005,9 @@
 
     public Bundle getAppWidgetOptions(int appWidgetId) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return Bundle.EMPTY;
+            }
             ensureStateLoadedLocked();
             AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
             if (id != null && id.options != null) {
@@ -964,6 +1019,9 @@
     }
 
     public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
+        if (!mHasFeature) {
+            return;
+        }
         if (appWidgetIds == null) {
             return;
         }
@@ -987,6 +1045,9 @@
     }
 
     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
+        if (!mHasFeature) {
+            return;
+        }
         if (appWidgetIds == null) {
             return;
         }
@@ -1005,6 +1066,9 @@
     }
 
     public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
+        if (!mHasFeature) {
+            return;
+        }
         synchronized (mAppWidgetIds) {
             ensureStateLoadedLocked();
             Provider p = lookupProviderLocked(provider);
@@ -1147,6 +1211,9 @@
 
     public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
             List<RemoteViews> updatedViews) {
+        if (!mHasFeature) {
+            return new int[0];
+        }
         int callingUid = enforceCallingUid(packageName);
         synchronized (mAppWidgetIds) {
             ensureStateLoadedLocked();
@@ -1169,6 +1236,9 @@
 
     public void stopListening(int hostId) {
         synchronized (mAppWidgetIds) {
+            if (!mHasFeature) {
+                return;
+            }
             ensureStateLoadedLocked();
             Host host = lookupHostLocked(Binder.getCallingUid(), hostId);
             if (host != null) {
@@ -1558,6 +1628,9 @@
     }
 
     void saveStateLocked() {
+        if (!mHasFeature) {
+            return;
+        }
         AtomicFile file = savedStateFile();
         FileOutputStream stream;
         try {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 401a25f..2a3c87e 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -63,6 +63,7 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -78,6 +79,7 @@
 
 import com.android.internal.backup.BackupConstants;
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.backup.IObbBackupService;
 import com.android.internal.backup.LocalTransport;
 import com.android.server.PackageManagerBackupAgent.Metadata;
 
@@ -363,15 +365,17 @@
 
     class FullBackupParams extends FullParams {
         public boolean includeApks;
+        public boolean includeObbs;
         public boolean includeShared;
         public boolean allApps;
         public boolean includeSystem;
         public String[] packages;
 
-        FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveShared,
-                boolean doAllApps, boolean doSystem, String[] pkgList) {
+        FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
+                boolean saveShared, boolean doAllApps, boolean doSystem, String[] pkgList) {
             fd = output;
             includeApks = saveApks;
+            includeObbs = saveObbs;
             includeShared = saveShared;
             allApps = doAllApps;
             includeSystem = doSystem;
@@ -550,7 +554,7 @@
                 // similar to normal backup/restore.
                 FullBackupParams params = (FullBackupParams)msg.obj;
                 PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
-                        params.observer, params.includeApks,
+                        params.observer, params.includeApks, params.includeObbs,
                         params.includeShared, params.curPassword, params.encryptPassword,
                         params.allApps, params.includeSystem, params.packages, params.latch);
                 (new Thread(task)).start();
@@ -743,6 +747,9 @@
         // correct directory.
         mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
         mBaseStateDir.mkdirs();
+        if (!SELinux.restorecon(mBaseStateDir)) {
+            Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
+        }
         mDataDir = Environment.getDownloadCacheDirectory();
 
         mPasswordHashFile = new File(mBaseStateDir, "pwhash");
@@ -2133,6 +2140,10 @@
                         ParcelFileDescriptor.MODE_CREATE |
                         ParcelFileDescriptor.MODE_TRUNCATE);
 
+                if (!SELinux.restorecon(mBackupDataName)) {
+                    Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName);
+                }
+
                 mNewState = ParcelFileDescriptor.open(mNewStateName,
                         ParcelFileDescriptor.MODE_READ_WRITE |
                         ParcelFileDescriptor.MODE_CREATE |
@@ -2306,13 +2317,132 @@
     }
 
 
-    // ----- Full backup to a file/socket -----
+    // ----- Full backup/restore to a file/socket -----
 
-    class PerformFullBackupTask implements Runnable {
+    abstract class ObbServiceClient {
+        public IObbBackupService mObbService;
+        public void setObbBinder(IObbBackupService binder) {
+            mObbService = binder;
+        }
+    }
+
+    class FullBackupObbConnection implements ServiceConnection {
+        volatile IObbBackupService mService;
+
+        FullBackupObbConnection() {
+            mService = null;
+        }
+
+        public void establish() {
+            if (DEBUG) Slog.i(TAG, "Initiating bind of OBB service on " + this);
+            Intent obbIntent = new Intent().setComponent(new ComponentName(
+                    "com.android.sharedstoragebackup",
+                    "com.android.sharedstoragebackup.ObbBackupService"));
+            BackupManagerService.this.mContext.bindService(
+                    obbIntent, this, Context.BIND_AUTO_CREATE);
+        }
+
+        public void tearDown() {
+            BackupManagerService.this.mContext.unbindService(this);
+        }
+
+        public boolean backupObbs(PackageInfo pkg, OutputStream out) {
+            boolean success = false;
+            waitForConnection();
+
+            ParcelFileDescriptor[] pipes = null;
+            try {
+                pipes = ParcelFileDescriptor.createPipe();
+                int token = generateToken();
+                prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
+                mService.backupObbs(pkg.packageName, pipes[1], token, mBackupManagerBinder);
+                routeSocketDataToOutput(pipes[0], out);
+                success = waitUntilOperationComplete(token);
+            } catch (Exception e) {
+                Slog.w(TAG, "Unable to back up OBBs for " + pkg, e);
+            } finally {
+                try {
+                    out.flush();
+                    if (pipes != null) {
+                        if (pipes[0] != null) pipes[0].close();
+                        if (pipes[1] != null) pipes[1].close();
+                    }
+                } catch (IOException e) {
+                    Slog.w(TAG, "I/O error closing down OBB backup", e);
+                }
+            }
+            return success;
+        }
+
+        public void restoreObbFile(String pkgName, ParcelFileDescriptor data,
+                long fileSize, int type, String path, long mode, long mtime,
+                int token, IBackupManager callbackBinder) {
+            waitForConnection();
+
+            try {
+                mService.restoreObbFile(pkgName, data, fileSize, type, path, mode, mtime,
+                        token, callbackBinder);
+            } catch (Exception e) {
+                Slog.w(TAG, "Unable to restore OBBs for " + pkgName, e);
+            }
+        }
+
+        private void waitForConnection() {
+            synchronized (this) {
+                while (mService == null) {
+                    if (DEBUG) Slog.i(TAG, "...waiting for OBB service binding...");
+                    try {
+                        this.wait();
+                    } catch (InterruptedException e) { /* never interrupted */ }
+                }
+                if (DEBUG) Slog.i(TAG, "Connected to OBB service; continuing");
+            }
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (this) {
+                mService = IObbBackupService.Stub.asInterface(service);
+                if (DEBUG) Slog.i(TAG, "OBB service connection " + mService
+                        + " connected on " + this);
+                this.notifyAll();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (this) {
+                mService = null;
+                if (DEBUG) Slog.i(TAG, "OBB service connection disconnected on " + this);
+                this.notifyAll();
+            }
+        }
+        
+    }
+
+    private void routeSocketDataToOutput(ParcelFileDescriptor inPipe, OutputStream out)
+            throws IOException {
+        FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor());
+        DataInputStream in = new DataInputStream(raw);
+
+        byte[] buffer = new byte[32 * 1024];
+        int chunkTotal;
+        while ((chunkTotal = in.readInt()) > 0) {
+            while (chunkTotal > 0) {
+                int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
+                int nRead = in.read(buffer, 0, toRead);
+                out.write(buffer, 0, nRead);
+                chunkTotal -= nRead;
+            }
+        }
+    }
+
+    class PerformFullBackupTask extends ObbServiceClient implements Runnable {
         ParcelFileDescriptor mOutputFile;
         DeflaterOutputStream mDeflater;
         IFullBackupRestoreObserver mObserver;
         boolean mIncludeApks;
+        boolean mIncludeObbs;
         boolean mIncludeShared;
         boolean mAllApps;
         final boolean mIncludeSystem;
@@ -2322,6 +2452,7 @@
         AtomicBoolean mLatchObject;
         File mFilesDir;
         File mManifestFile;
+        
 
         class FullBackupRunner implements Runnable {
             PackageInfo mPackage;
@@ -2377,12 +2508,13 @@
         }
 
         PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer, 
-                boolean includeApks, boolean includeShared, String curPassword,
-                String encryptPassword, boolean doAllApps, boolean doSystem, String[] packages,
-                AtomicBoolean latch) {
+                boolean includeApks, boolean includeObbs, boolean includeShared,
+                String curPassword, String encryptPassword, boolean doAllApps,
+                boolean doSystem, String[] packages, AtomicBoolean latch) {
             mOutputFile = fd;
             mObserver = observer;
             mIncludeApks = includeApks;
+            mIncludeObbs = includeObbs;
             mIncludeShared = includeShared;
             mAllApps = doAllApps;
             mIncludeSystem = doSystem;
@@ -2405,9 +2537,12 @@
 
         @Override
         public void run() {
-            List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
-
             Slog.i(TAG, "--- Performing full-dataset backup ---");
+
+            List<PackageInfo> packagesToBackup = new ArrayList<PackageInfo>();
+            FullBackupObbConnection obbConnection = new FullBackupObbConnection();
+            obbConnection.establish();  // we'll want this later
+
             sendStartBackup();
 
             // doAllApps supersedes the package set if any
@@ -2557,6 +2692,15 @@
                 for (int i = 0; i < N; i++) {
                     pkg = packagesToBackup.get(i);
                     backupOnePackage(pkg, out);
+
+                    // after the app's agent runs to handle its private filesystem
+                    // contents, back up any OBB content it has on its behalf.
+                    if (mIncludeObbs) {
+                        boolean obbOkay = obbConnection.backupObbs(pkg, out);
+                        if (!obbOkay) {
+                            throw new RuntimeException("Failure writing OBB stack for " + pkg);
+                        }
+                    }
                 }
 
                 // Done!
@@ -2581,6 +2725,7 @@
                     mLatchObject.notifyAll();
                 }
                 sendEndBackup();
+                obbConnection.tearDown();
                 if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
                 mWakelock.release();
             }
@@ -2688,20 +2833,7 @@
 
                     // Now pull data from the app and stuff it into the compressor
                     try {
-                        FileInputStream raw = new FileInputStream(pipes[0].getFileDescriptor());
-                        DataInputStream in = new DataInputStream(raw);
-
-                        byte[] buffer = new byte[16 * 1024];
-                        int chunkTotal;
-                        while ((chunkTotal = in.readInt()) > 0) {
-                            while (chunkTotal > 0) {
-                                int toRead = (chunkTotal > buffer.length)
-                                        ? buffer.length : chunkTotal;
-                                int nRead = in.read(buffer, 0, toRead);
-                                out.write(buffer, 0, nRead);
-                                chunkTotal -= nRead;
-                            }
-                        }
+                        routeSocketDataToOutput(pipes[0], out);
                     } catch (IOException e) {
                         Slog.i(TAG, "Caught exception reading from agent", e);
                     }
@@ -2900,7 +3032,7 @@
         ACCEPT_IF_APK
     }
 
-    class PerformFullRestoreTask implements Runnable {
+    class PerformFullRestoreTask extends ObbServiceClient implements Runnable {
         ParcelFileDescriptor mInputFile;
         String mCurrentPassword;
         String mDecryptPassword;
@@ -2909,6 +3041,7 @@
         IBackupAgent mAgent;
         String mAgentPackage;
         ApplicationInfo mTargetApp;
+        FullBackupObbConnection mObbConnection = null;
         ParcelFileDescriptor[] mPipes = null;
 
         long mBytes;
@@ -2937,6 +3070,7 @@
             mAgent = null;
             mAgentPackage = null;
             mTargetApp = null;
+            mObbConnection = new FullBackupObbConnection();
 
             // Which packages we've already wiped data on.  We prepopulate this
             // with a whitelist of packages known to be unclearable.
@@ -2980,6 +3114,7 @@
         @Override
         public void run() {
             Slog.i(TAG, "--- Performing full-dataset restore ---");
+            mObbConnection.establish();
             sendStartRestore();
 
             // Are we able to restore shared-storage data?
@@ -3067,6 +3202,7 @@
                     mLatchObject.set(true);
                     mLatchObject.notifyAll();
                 }
+                mObbConnection.tearDown();
                 sendEndRestore();
                 Slog.d(TAG, "Full restore pass complete.");
                 mWakelock.release();
@@ -3319,22 +3455,30 @@
                             long toCopy = info.size;
                             final int token = generateToken();
                             try {
-                                if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
-                                        + info.path);
                                 prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL, null);
-                                // fire up the app's agent listening on the socket.  If
-                                // the agent is running in the system process we can't
-                                // just invoke it asynchronously, so we provide a thread
-                                // for it here.
-                                if (mTargetApp.processName.equals("system")) {
-                                    Slog.d(TAG, "system process agent - spinning a thread");
-                                    RestoreFileRunnable runner = new RestoreFileRunnable(
-                                            mAgent, info, mPipes[0], token);
-                                    new Thread(runner).start();
+                                if (info.domain.equals(FullBackup.OBB_TREE_TOKEN)) {
+                                    if (DEBUG) Slog.d(TAG, "Restoring OBB file for " + pkg
+                                            + " : " + info.path);
+                                    mObbConnection.restoreObbFile(pkg, mPipes[0],
+                                            info.size, info.type, info.path, info.mode,
+                                            info.mtime, token, mBackupManagerBinder);
                                 } else {
-                                    mAgent.doRestoreFile(mPipes[0], info.size, info.type,
-                                            info.domain, info.path, info.mode, info.mtime,
-                                            token, mBackupManagerBinder);
+                                    if (DEBUG) Slog.d(TAG, "Invoking agent to restore file "
+                                            + info.path);
+                                    // fire up the app's agent listening on the socket.  If
+                                    // the agent is running in the system process we can't
+                                    // just invoke it asynchronously, so we provide a thread
+                                    // for it here.
+                                    if (mTargetApp.processName.equals("system")) {
+                                        Slog.d(TAG, "system process agent - spinning a thread");
+                                        RestoreFileRunnable runner = new RestoreFileRunnable(
+                                                mAgent, info, mPipes[0], token);
+                                        new Thread(runner).start();
+                                    } else {
+                                        mAgent.doRestoreFile(mPipes[0], info.size, info.type,
+                                                info.domain, info.path, info.mode, info.mtime,
+                                                token, mBackupManagerBinder);
+                                    }
                                 }
                             } catch (IOException e) {
                                 // couldn't dup the socket for a process-local restore
@@ -3342,7 +3486,7 @@
                                 agentSuccess = false;
                                 okay = false;
                             } catch (RemoteException e) {
-                                // whoops, remote agent went away.  We'll eat the content
+                                // whoops, remote entity went away.  We'll eat the content
                                 // ourselves, then, and not copy it over.
                                 Slog.e(TAG, "Agent crashed during full restore");
                                 agentSuccess = false;
@@ -3795,7 +3939,7 @@
                 b.append(String.format(" %9d ", info.size));
 
                 Date stamp = new Date(info.mtime);
-                b.append(new SimpleDateFormat("MMM dd kk:mm:ss ").format(stamp));
+                b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp));
 
                 b.append(info.packageName);
                 b.append(" :: ");
@@ -3891,18 +4035,6 @@
                             slash = info.path.indexOf('/');
                             if (slash < 0) throw new IOException("Illegal semantic path in non-manifest " + info.path);
                             info.domain = info.path.substring(0, slash);
-                            // validate that it's one of the domains we understand
-                            if (!info.domain.equals(FullBackup.APK_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.DATA_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.DATABASE_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.ROOT_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.OBB_TREE_TOKEN)
-                                    && !info.domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
-                                throw new IOException("Unrecognized domain " + info.domain);
-                            }
-
                             info.path = info.path.substring(slash + 1);
                         }
                     }
@@ -4573,6 +4705,10 @@
                             ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE);
 
+                if (!SELinux.restorecon(mBackupDataName)) {
+                    Slog.e(TAG, "SElinux restorecon failed for " + mBackupDataName);
+                }
+
                 if (mTransport.getRestoreData(mBackupData) != BackupConstants.TRANSPORT_OK) {
                     // Transport-level failure, so we wind everything up and
                     // terminate the restore operation.
@@ -4989,7 +5125,8 @@
     // Run a *full* backup pass for the given package, writing the resulting data stream
     // to the supplied file descriptor.  This method is synchronous and does not return
     // to the caller until the backup has been completed.
-    public void fullBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeShared,
+    public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
+            boolean includeObbs, boolean includeShared,
             boolean doAllApps, boolean includeSystem, String[] pkgList) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
 
@@ -5020,12 +5157,12 @@
             }
 
             if (DEBUG) Slog.v(TAG, "Requesting full backup: apks=" + includeApks
-                    + " shared=" + includeShared + " all=" + doAllApps
+                    + " obb=" + includeObbs + " shared=" + includeShared + " all=" + doAllApps
                     + " pkgs=" + pkgList);
             Slog.i(TAG, "Beginning full backup...");
 
-            FullBackupParams params = new FullBackupParams(fd, includeApks, includeShared,
-                    doAllApps, includeSystem, pkgList);
+            FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
+                    includeShared, doAllApps, includeSystem, pkgList);
             final int token = generateToken();
             synchronized (mFullConfirmations) {
                 mFullConfirmations.put(token, params);
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
old mode 100755
new mode 100644
index 33e712a..ea7b696
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothGatt;
 import android.bluetooth.IBluetoothCallback;
 import android.bluetooth.IBluetoothManager;
 import android.bluetooth.IBluetoothManagerCallback;
@@ -87,6 +88,9 @@
     // and Airplane mode will have higher priority.
     private static final int BLUETOOTH_ON_AIRPLANE=2;
 
+    private static final int SERVICE_IBLUETOOTH = 1;
+    private static final int SERVICE_IBLUETOOTHGATT = 2;
+
     private final Context mContext;
 
     // Locks are not provided for mName and mAddress.
@@ -97,6 +101,7 @@
     private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
     private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
     private IBluetooth mBluetooth;
+    private IBluetoothGatt mBluetoothGatt;
     private boolean mBinding;
     private boolean mUnbinding;
     // used inside handler thread
@@ -463,6 +468,11 @@
         }
     }
 
+    public IBluetoothGatt getBluetoothGatt() {
+        // sync protection
+        return mBluetoothGatt;
+    }
+
     private void sendBluetoothStateCallback(boolean isUp) {
         int n = mStateChangeCallbacks.beginBroadcast();
         if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
@@ -575,16 +585,35 @@
         }
 
         public void onServiceConnected(ComponentName className, IBinder service) {
-            if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
+            if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
+            // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
+            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
+                msg.arg1 = SERVICE_IBLUETOOTH;
+                // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
+            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
+                msg.arg1 = SERVICE_IBLUETOOTHGATT;
+            } else {
+                Log.e(TAG, "Unknown service connected: " + className.getClassName());
+                return;
+            }
             msg.obj = service;
             mHandler.sendMessage(msg);
         }
 
         public void onServiceDisconnected(ComponentName className) {
             // Called if we unexpected disconnected.
-            if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
+            if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
+                           className.getClassName());
             Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
+            if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
+                msg.arg1 = SERVICE_IBLUETOOTH;
+            } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
+                msg.arg1 = SERVICE_IBLUETOOTHGATT;
+            } else {
+                Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
+                return;
+            }
             mHandler.sendMessage(msg);
         }
     }
@@ -746,13 +775,18 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                 {
-                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
-
-                    //Remove timeout
-                    mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
 
                     IBinder service = (IBinder) msg.obj;
                     synchronized(mConnection) {
+                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
+                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
+                            break;
+                        } // else must be SERVICE_IBLUETOOTH
+
+                        //Remove timeout
+                            mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+
                         mBinding = false;
                         mBluetooth = IBluetooth.Stub.asInterface(service);
 
@@ -816,11 +850,19 @@
                 }
                 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
                 {
-                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
+                    Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
                     synchronized(mConnection) {
-                        // if service is unbinded already, do nothing and return
-                        if (mBluetooth == null) return;
-                        mBluetooth = null;
+                        if (msg.arg1 == SERVICE_IBLUETOOTH) {
+                            // if service is unbinded already, do nothing and return
+                            if (mBluetooth == null) break;
+                            mBluetooth = null;
+                        } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
+                            mBluetoothGatt = null;
+                            break;
+                        } else {
+                            Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
+                            break;
+                        }
                     }
 
                     if (mEnable) {
@@ -1048,10 +1090,19 @@
                 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
                 sendBluetoothStateCallback(isUp);
 
-                //If Bluetooth is off, send service down event to proxy objects, and unbind
-                if (!isUp && canUnbindBluetoothService()) {
-                    sendBluetoothServiceDownCallback();
-                    unbindAndFinish();
+                if (isUp) {
+                    // connect to GattService
+                    Intent i = new Intent(IBluetoothGatt.class.getName());
+                    if (!mContext.bindServiceAsUser(i, mConnection, Context.BIND_AUTO_CREATE,
+                                                    UserHandle.CURRENT)) {
+                        Log.e(TAG, "Fail to bind to: " + IBluetoothGatt.class.getName());
+                    }
+                } else {
+                    //If Bluetooth is off, send service down event to proxy objects, and unbind
+                    if (!isUp && canUnbindBluetoothService()) {
+                        sendBluetoothServiceDownCallback();
+                        unbindAndFinish();
+                    }
                 }
             }
 
@@ -1081,9 +1132,9 @@
                         if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
                     } else if (off) {
                         if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
-		    } else {
+                    } else {
                         if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
-		    }
+                    }
                 } catch (RemoteException e) {
                     Log.e(TAG, "getState()", e);
                     break;
@@ -1091,9 +1142,9 @@
             }
             if (on || off) {
                 SystemClock.sleep(300);
-	    } else {
+            } else {
                 SystemClock.sleep(50);
-	    }
+            }
             i++;
         }
         Log.e(TAG,"waitForOnOff time out");
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 3257d2c..ffc3672 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -74,6 +74,7 @@
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.Process;
@@ -96,6 +97,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.connectivity.Nat464Xlat;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
@@ -154,6 +156,8 @@
     private boolean mLockdownEnabled;
     private LockdownVpnTracker mLockdownTracker;
 
+    private Nat464Xlat mClat;
+
     /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
     private Object mRulesLock = new Object();
     /** Currently active network rules by UID. */
@@ -317,12 +321,11 @@
 
     // track the current default http proxy - tell the world if we get a new one (real change)
     private ProxyProperties mDefaultProxy = null;
-    private Object mDefaultProxyLock = new Object();
+    private Object mProxyLock = new Object();
     private boolean mDefaultProxyDisabled = false;
 
     // track the global proxy.
     private ProxyProperties mGlobalProxy = null;
-    private final Object mGlobalProxyLock = new Object();
 
     private SettingsObserver mSettingsObserver;
 
@@ -544,9 +547,12 @@
         mVpn = new Vpn(mContext, mVpnCallback, mNetd);
         mVpn.startMonitoring(mContext, mTrackerHandler);
 
+        mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
+
         try {
             mNetd.registerObserver(mTethering);
             mNetd.registerObserver(mDataActivityObserver);
+            mNetd.registerObserver(mClat);
         } catch (RemoteException e) {
             loge("Error registering observer :" + e);
         }
@@ -1413,11 +1419,11 @@
     }
 
     private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable);
+        return modifyRoute(p, r, 0, ADD, toDefaultTable);
     }
 
     private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
-        return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable);
+        return modifyRoute(p, r, 0, REMOVE, toDefaultTable);
     }
 
     private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
@@ -1430,26 +1436,27 @@
 
     private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
             boolean toDefaultTable) {
-        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
+        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
         if (bestRoute == null) {
-            bestRoute = RouteInfo.makeHostRoute(addr);
+            bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
         } else {
+            String iface = bestRoute.getInterface();
             if (bestRoute.getGateway().equals(addr)) {
                 // if there is no better route, add the implied hostroute for our gateway
-                bestRoute = RouteInfo.makeHostRoute(addr);
+                bestRoute = RouteInfo.makeHostRoute(addr, iface);
             } else {
                 // if we will connect to this through another route, add a direct route
                 // to it's gateway
-                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
+                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
             }
         }
-        return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable);
+        return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable);
     }
 
-    private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
-            boolean doAdd, boolean toDefaultTable) {
-        if ((ifaceName == null) || (lp == null) || (r == null)) {
-            if (DBG) log("modifyRoute got unexpected null: " + ifaceName + ", " + lp + ", " + r);
+    private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd,
+            boolean toDefaultTable) {
+        if ((lp == null) || (r == null)) {
+            if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r);
             return false;
         }
 
@@ -1458,18 +1465,26 @@
             return false;
         }
 
+        String ifaceName = r.getInterface();
+        if(ifaceName == null) {
+            loge("Error modifying route - no interface name");
+            return false;
+        }
+
         if (r.isHostRoute() == false) {
-            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
+            RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway());
             if (bestRoute != null) {
                 if (bestRoute.getGateway().equals(r.getGateway())) {
                     // if there is no better route, add the implied hostroute for our gateway
-                    bestRoute = RouteInfo.makeHostRoute(r.getGateway());
+                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), ifaceName);
                 } else {
                     // if we will connect to our gateway through another route, add a direct
                     // route to it's gateway
-                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
+                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(),
+                                                        bestRoute.getGateway(),
+                                                        ifaceName);
                 }
-                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
+                modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
             }
         }
         if (doAdd) {
@@ -2241,32 +2256,52 @@
         if (resetMask != 0 || resetDns) {
             LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
             if (linkProperties != null) {
-                String iface = linkProperties.getInterfaceName();
-                if (TextUtils.isEmpty(iface) == false) {
-                    if (resetMask != 0) {
-                        if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
-                        NetworkUtils.resetConnections(iface, resetMask);
+                for (String iface : linkProperties.getAllInterfaceNames()) {
+                    if (TextUtils.isEmpty(iface) == false) {
+                        if (resetMask != 0) {
+                            if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
+                            NetworkUtils.resetConnections(iface, resetMask);
 
-                        // Tell VPN the interface is down. It is a temporary
-                        // but effective fix to make VPN aware of the change.
-                        if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
-                            mVpn.interfaceStatusChanged(iface, false);
+                            // Tell VPN the interface is down. It is a temporary
+                            // but effective fix to make VPN aware of the change.
+                            if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) {
+                                mVpn.interfaceStatusChanged(iface, false);
+                            }
                         }
-                    }
-                    if (resetDns) {
-                        flushVmDnsCache();
-                        if (VDBG) log("resetting DNS cache for " + iface);
-                        try {
-                            mNetd.flushInterfaceDnsCache(iface);
-                        } catch (Exception e) {
-                            // never crash - catch them all
-                            if (DBG) loge("Exception resetting dns cache: " + e);
+                        if (resetDns) {
+                            flushVmDnsCache();
+                            if (VDBG) log("resetting DNS cache for " + iface);
+                            try {
+                                mNetd.flushInterfaceDnsCache(iface);
+                            } catch (Exception e) {
+                                // never crash - catch them all
+                                if (DBG) loge("Exception resetting dns cache: " + e);
+                            }
                         }
                     }
                 }
             }
         }
 
+        // Update 464xlat state.
+        NetworkStateTracker tracker = mNetTrackers[netType];
+        if (mClat.requiresClat(netType, tracker)) {
+            // If the connection was previously using clat, but is not using it now, stop the clat
+            // daemon. Normally, this happens automatically when the connection disconnects, but if
+            // the disconnect is not reported, or if the connection's LinkProperties changed for
+            // some other reason (e.g., handoff changes the IP addresses on the link), it would
+            // still be running. If it's not running, then stopping it is a no-op.
+            if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) {
+                mClat.stopClat();
+            }
+            // If the link requires clat to be running, then start the daemon now.
+            if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+                mClat.startClat(tracker);
+            } else {
+                mClat.stopClat();
+            }
+        }
+
         // TODO: Temporary notifying upstread change to Tethering.
         //       @see bug/4455071
         /** Notify TetheringService if interface name has been changed. */
@@ -2296,7 +2331,7 @@
             routeDiff = curLp.compareRoutes(newLp);
             dnsDiff = curLp.compareDnses(newLp);
         } else if (newLp != null) {
-            routeDiff.added = newLp.getRoutes();
+            routeDiff.added = newLp.getAllRoutes();
             dnsDiff.added = newLp.getDnses();
         }
 
@@ -3003,14 +3038,15 @@
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
         // enforceAccessPermission();
-        synchronized (mDefaultProxyLock) {
-            return mDefaultProxyDisabled ? null : mDefaultProxy;
+        synchronized (mProxyLock) {
+            if (mGlobalProxy != null) return mGlobalProxy;
+            return (mDefaultProxyDisabled ? null : mDefaultProxy);
         }
     }
 
     public void setGlobalProxy(ProxyProperties proxyProperties) {
         enforceChangePermission();
-        synchronized (mGlobalProxyLock) {
+        synchronized (mProxyLock) {
             if (proxyProperties == mGlobalProxy) return;
             if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
             if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
@@ -3036,7 +3072,7 @@
         if (mGlobalProxy == null) {
             proxyProperties = mDefaultProxy;
         }
-        //sendProxyBroadcast(proxyProperties);
+        sendProxyBroadcast(proxyProperties);
     }
 
     private void loadGlobalProxy() {
@@ -3047,7 +3083,7 @@
                 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
         if (!TextUtils.isEmpty(host)) {
             ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
-            synchronized (mGlobalProxyLock) {
+            synchronized (mProxyLock) {
                 mGlobalProxy = proxyProperties;
             }
         }
@@ -3058,7 +3094,7 @@
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
         // enforceAccessPermission();
-        synchronized (mGlobalProxyLock) {
+        synchronized (mProxyLock) {
             return mGlobalProxy;
         }
     }
@@ -3067,11 +3103,12 @@
         if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
             proxy = null;
         }
-        synchronized (mDefaultProxyLock) {
+        synchronized (mProxyLock) {
             if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
-            if (mDefaultProxy == proxy) return;
+            if (mDefaultProxy == proxy) return; // catches repeated nulls
             mDefaultProxy = proxy;
 
+            if (mGlobalProxy != null) return;
             if (!mDefaultProxyDisabled) {
                 sendProxyBroadcast(proxy);
             }
@@ -3193,7 +3230,7 @@
         throwIfLockdownEnabled();
         try {
             int type = mActiveDefaultNetwork;
-            if (ConnectivityManager.isNetworkTypeValid(type)) {
+            if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
                 mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
                 return true;
             }
@@ -3314,10 +3351,10 @@
                 mDnsOverridden = true;
             }
 
-            // Temporarily disable the default proxy.
-            synchronized (mDefaultProxyLock) {
+            // Temporarily disable the default proxy (not global).
+            synchronized (mProxyLock) {
                 mDefaultProxyDisabled = true;
-                if (mDefaultProxy != null) {
+                if (mGlobalProxy == null && mDefaultProxy != null) {
                     sendProxyBroadcast(null);
                 }
             }
@@ -3332,9 +3369,9 @@
                     mHandler.sendEmptyMessage(EVENT_RESTORE_DNS);
                 }
             }
-            synchronized (mDefaultProxyLock) {
+            synchronized (mProxyLock) {
                 mDefaultProxyDisabled = false;
-                if (mDefaultProxy != null) {
+                if (mGlobalProxy == null && mDefaultProxy != null) {
                     sendProxyBroadcast(mDefaultProxy);
                 }
             }
@@ -3398,4 +3435,12 @@
             throw new IllegalStateException("Unavailable in lockdown mode");
         }
     }
+
+    public void supplyMessenger(int networkType, Messenger messenger) {
+        enforceConnectivityInternalPermission();
+
+        if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) {
+            mNetTrackers[networkType].supplyMessenger(messenger);
+        }
+    }
 }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 18b4ec1..ab70e6f 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -41,10 +41,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.Signature;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -62,6 +66,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.AtomicFile;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.Slog;
@@ -88,10 +93,11 @@
  * Implementation of the device policy APIs.
  */
 public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
-    private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
     private static final String TAG = "DevicePolicyManagerService";
 
+    private static final String DEVICE_POLICIES_XML = "device_policies.xml";
+
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
     private static final long MS_PER_DAY = 86400 * 1000;
@@ -109,6 +115,8 @@
     IPowerManager mIPowerManager;
     IWindowManager mIWindowManager;
 
+    private DeviceOwner mDeviceOwner;
+
     public static class DevicePolicyData {
         int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         int mActivePasswordLength = 0;
@@ -507,6 +515,7 @@
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addDataScheme("package");
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
     }
@@ -545,6 +554,14 @@
         }
     }
 
+    void loadDeviceOwner() {
+        synchronized (this) {
+            if (DeviceOwner.isRegistered()) {
+                mDeviceOwner = new DeviceOwner();
+            }
+        }
+    }
+
     /**
      * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
      * reminders.  Clears alarm if no expirations are configured.
@@ -709,7 +726,9 @@
         Intent resolveIntent = new Intent();
         resolveIntent.setComponent(adminName);
         List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
-                resolveIntent, PackageManager.GET_META_DATA, userHandle);
+                resolveIntent,
+                PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+                userHandle);
         if (infos == null || infos.size() <= 0) {
             throw new IllegalArgumentException("Unknown admin: " + adminName);
         }
@@ -994,6 +1013,7 @@
     public void systemReady() {
         synchronized (this) {
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
+            loadDeviceOwner();
         }
     }
 
@@ -1052,6 +1072,7 @@
                 }
                 if (replaceIndex == -1) {
                     policy.mAdminList.add(newAdmin);
+                    enableIfNecessary(info.getPackageName(), userHandle);
                 } else {
                     policy.mAdminList.set(replaceIndex, newAdmin);
                 }
@@ -1119,6 +1140,11 @@
                 return;
             }
             if (admin.getUid() != Binder.getCallingUid()) {
+                // If trying to remove device owner, refuse when the caller is not the owner.
+                if (mDeviceOwner != null
+                        && adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
+                    return;
+                }
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.BIND_DEVICE_ADMIN, null);
             }
@@ -2351,6 +2377,49 @@
         }
     }
 
+    @Override
+    public boolean setDeviceOwner(String packageName) {
+        if (packageName == null
+                || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
+            throw new IllegalArgumentException("Invalid package name " + packageName
+                    + " for device owner");
+        }
+        synchronized (this) {
+            if (mDeviceOwner == null && !isDeviceProvisioned()) {
+                mDeviceOwner = new DeviceOwner(packageName);
+                mDeviceOwner.writeOwnerFile();
+                return true;
+            } else {
+                throw new IllegalStateException("Trying to set device owner to " + packageName
+                        + ", owner=" + mDeviceOwner.getPackageName()
+                        + ", device_provisioned=" + isDeviceProvisioned());
+            }
+        }
+    }
+
+    @Override
+    public boolean isDeviceOwner(String packageName) {
+        synchronized (this) {
+            return mDeviceOwner != null
+                    && mDeviceOwner.getPackageName().equals(packageName);
+        }
+    }
+
+    @Override
+    public String getDeviceOwner() {
+        synchronized (this) {
+            if (mDeviceOwner != null) {
+                return mDeviceOwner.getPackageName();
+            }
+        }
+        return null;
+    }
+
+    private boolean isDeviceProvisioned() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) > 0;
+    }
+
     private void enforceCrossUserPermission(int userHandle) {
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
@@ -2364,6 +2433,22 @@
         }
     }
 
+    private void enableIfNecessary(String packageName, int userId) {
+        try {
+            IPackageManager ipm = AppGlobals.getPackageManager();
+            ApplicationInfo ai = ipm.getApplicationInfo(packageName,
+                    PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
+                    userId);
+            if (ai.enabledSetting
+                    == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                ipm.setApplicationEnabledSetting(packageName,
+                        PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+                        PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -2399,4 +2484,92 @@
             }
         }
     }
+
+    static class DeviceOwner {
+        private static final String DEVICE_OWNER_XML = "device_owner.xml";
+        private static final String TAG_DEVICE_OWNER = "device-owner";
+        private static final String ATTR_PACKAGE = "package";
+        private String mPackageName;
+
+        DeviceOwner() {
+            readOwnerFile();
+        }
+
+        DeviceOwner(String packageName) {
+            this.mPackageName = packageName;
+        }
+
+        static boolean isRegistered() {
+            return new File(Environment.getSystemSecureDirectory(),
+                    DEVICE_OWNER_XML).exists();
+        }
+
+        String getPackageName() {
+            return mPackageName;
+        }
+
+        static boolean isInstalled(String packageName, PackageManager pm) {
+            try {
+                PackageInfo pi;
+                if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
+                    if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        return true;
+                    }
+                }
+            } catch (NameNotFoundException nnfe) {
+                Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+            }
+            return false;
+        }
+
+        void readOwnerFile() {
+            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                    DEVICE_OWNER_XML));
+            try {
+                FileInputStream input = file.openRead();
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(input, null);
+                int type;
+                while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                        && type != XmlPullParser.START_TAG) {
+                }
+                String tag = parser.getName();
+                if (!TAG_DEVICE_OWNER.equals(tag)) {
+                    throw new XmlPullParserException(
+                            "Device Owner file does not start with device-owner tag: found " + tag);
+                }
+                mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                input.close();
+            } catch (XmlPullParserException xppe) {
+                Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+            } catch (IOException ioe) {
+                Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+            }
+        }
+
+        void writeOwnerFile() {
+            synchronized (this) {
+                writeOwnerFileLocked();
+            }
+        }
+
+        private void writeOwnerFileLocked() {
+            AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
+                    DEVICE_OWNER_XML));
+            try {
+                FileOutputStream output = file.startWrite();
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(output, "utf-8");
+                out.startDocument(null, true);
+                out.startTag(null, TAG_DEVICE_OWNER);
+                out.attribute(null, ATTR_PACKAGE, mPackageName);
+                out.endTag(null, TAG_DEVICE_OWNER);
+                out.endDocument();
+                out.flush();
+                file.finishWrite(output);
+            } catch (IOException ioe) {
+                Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 8bc2da2..59577ad 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -157,3 +157,8 @@
 # ConfigUpdateInstallReceiver.java
 # ---------------------------
 51300 config_install_failed (dir|3)
+
+# ---------------------------
+# IntentFirewall.java
+# ---------------------------
+51400 ifw_intent_matched (Intent Type|1|5),(Component Name|3),(Caller Uid|1|5),(Caller Pkg Count|1|1),(Caller Pkgs|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 6ba5cff..a28c387 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -23,7 +23,7 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputSessionCallback;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
@@ -88,6 +88,7 @@
 import android.util.Slog;
 import android.util.Xml;
 import android.view.IWindowManager;
+import android.view.InputChannel;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -164,12 +165,13 @@
     final SettingsObserver mSettingsObserver;
     final IWindowManager mIWindowManager;
     final HandlerCaller mCaller;
+    final boolean mHasFeature;
     private InputMethodFileManager mFileManager;
     private InputMethodAndSubtypeListManager mImListManager;
     private final HardKeyboardListener mHardKeyboardListener;
     private final WindowManagerService mWindowManagerService;
 
-    final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
+    final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1);
 
     // All known input methods.  mMethodMap also serves as the global
     // lock for this class.
@@ -201,7 +203,9 @@
     class SessionState {
         final ClientState client;
         final IInputMethod method;
-        final IInputMethodSession session;
+
+        IInputMethodSession session;
+        InputChannel channel;
 
         @Override
         public String toString() {
@@ -210,18 +214,20 @@
                             System.identityHashCode(method))
                     + " session " + Integer.toHexString(
                             System.identityHashCode(session))
+                    + " channel " + channel
                     + "}";
         }
 
         SessionState(ClientState _client, IInputMethod _method,
-                IInputMethodSession _session) {
+                IInputMethodSession _session, InputChannel _channel) {
             client = _client;
             method = _method;
             session = _session;
+            channel = _channel;
         }
     }
 
-    class ClientState {
+    static final class ClientState {
         final IInputMethodClient client;
         final IInputContext inputContext;
         final int uid;
@@ -554,22 +560,21 @@
         }
     }
 
-    private static class MethodCallback extends IInputMethodCallback.Stub {
-        private final IInputMethod mMethod;
+    private static final class MethodCallback extends IInputSessionCallback.Stub {
         private final InputMethodManagerService mParentIMMS;
+        private final IInputMethod mMethod;
+        private final InputChannel mChannel;
 
-        MethodCallback(final IInputMethod method, final InputMethodManagerService imms) {
-            mMethod = method;
+        MethodCallback(InputMethodManagerService imms, IInputMethod method,
+                InputChannel channel) {
             mParentIMMS = imms;
+            mMethod = method;
+            mChannel = channel;
         }
 
         @Override
-        public void finishedEvent(int seq, boolean handled) throws RemoteException {
-        }
-
-        @Override
-        public void sessionCreated(IInputMethodSession session) throws RemoteException {
-            mParentIMMS.onSessionCreated(mMethod, session);
+        public void sessionCreated(IInputMethodSession session) {
+            mParentIMMS.onSessionCreated(mMethod, session, mChannel);
         }
     }
 
@@ -612,6 +617,8 @@
         }, true /*asyncHandler*/);
         mWindowManagerService = windowManager;
         mHardKeyboardListener = new HardKeyboardListener();
+        mHasFeature = context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_INPUT_METHODS);
 
         mImeSwitcherNotification = new Notification();
         mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
@@ -985,7 +992,10 @@
             return;
         }
         synchronized (mMethodMap) {
-            mClients.remove(client.asBinder());
+            ClientState cs = mClients.remove(client.asBinder());
+            if (cs != null) {
+                clearClientSessionLocked(cs);
+            }
         }
     }
 
@@ -1060,7 +1070,8 @@
             if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
             showCurrentInputLocked(getAppShowFlags(), null);
         }
-        return new InputBindResult(session.session, mCurId, mCurSeq);
+        return new InputBindResult(session.session,
+                session.channel != null ? session.channel.dup() : null, mCurId, mCurSeq);
     }
 
     InputBindResult startInputLocked(IInputMethodClient client,
@@ -1138,16 +1149,10 @@
             }
             if (mHaveConnection) {
                 if (mCurMethod != null) {
-                    if (!cs.sessionRequested) {
-                        cs.sessionRequested = true;
-                        if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
-                        executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
-                                MSG_CREATE_SESSION, mCurMethod,
-                                new MethodCallback(mCurMethod, this)));
-                    }
                     // Return to client, and we will get back with it when
                     // we have had a session made for it.
-                    return new InputBindResult(null, mCurId, mCurSeq);
+                    requestClientSessionLocked(cs);
+                    return new InputBindResult(null, null, mCurId, mCurSeq);
                 } else if (SystemClock.uptimeMillis()
                         < (mLastBindTime+TIME_TO_RECONNECT)) {
                     // In this case we have connected to the service, but
@@ -1157,7 +1162,7 @@
                     // we can report back.  If it has been too long, we want
                     // to fall through so we can try a disconnect/reconnect
                     // to see if we can get back in touch with the service.
-                    return new InputBindResult(null, mCurId, mCurSeq);
+                    return new InputBindResult(null, null, mCurId, mCurSeq);
                 } else {
                     EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
                             mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
@@ -1176,7 +1181,7 @@
         if (!mSystemReady) {
             // If the system is not yet ready, we shouldn't be running third
             // party code.
-            return new InputBindResult(null, mCurMethodId, mCurSeq);
+            return new InputBindResult(null, null, mCurMethodId, mCurSeq);
         }
 
         InputMethodInfo info = mMethodMap.get(mCurMethodId);
@@ -1199,12 +1204,12 @@
             mCurId = info.getId();
             mCurToken = new Binder();
             try {
-                if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
+                if (true || DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
                 mIWindowManager.addWindowToken(mCurToken,
                         WindowManager.LayoutParams.TYPE_INPUT_METHOD);
             } catch (RemoteException e) {
             }
-            return new InputBindResult(null, mCurId, mCurSeq);
+            return new InputBindResult(null, null, mCurId, mCurSeq);
         } else {
             mCurIntent = null;
             Slog.w(TAG, "Failure connecting to input method service: "
@@ -1247,32 +1252,34 @@
                 executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
                         MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
                 if (mCurClient != null) {
-                    if (DEBUG) Slog.v(TAG, "Creating first session while with client "
-                            + mCurClient);
-                    executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
-                            MSG_CREATE_SESSION, mCurMethod,
-                            new MethodCallback(mCurMethod, this)));
+                    clearClientSessionLocked(mCurClient);
+                    requestClientSessionLocked(mCurClient);
                 }
             }
         }
     }
 
-    void onSessionCreated(IInputMethod method, IInputMethodSession session) {
+    void onSessionCreated(IInputMethod method, IInputMethodSession session,
+            InputChannel channel) {
         synchronized (mMethodMap) {
             if (mCurMethod != null && method != null
                     && mCurMethod.asBinder() == method.asBinder()) {
                 if (mCurClient != null) {
+                    clearClientSessionLocked(mCurClient);
                     mCurClient.curSession = new SessionState(mCurClient,
-                            method, session);
-                    mCurClient.sessionRequested = false;
+                            method, session, channel);
                     InputBindResult res = attachNewInputLocked(true);
                     if (res.method != null) {
                         executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
                                 MSG_BIND_METHOD, mCurClient.client, res));
                     }
+                    return;
                 }
             }
         }
+
+        // Session abandoned.  Close its associated input channel.
+        channel.dispose();
     }
 
     void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) {
@@ -1307,14 +1314,38 @@
                     MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
         }
     }
-    
-    private void finishSession(SessionState sessionState) {
-        if (sessionState != null && sessionState.session != null) {
-            try {
-                sessionState.session.finishSession();
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Session failed to close due to remote exception", e);
-                setImeWindowVisibilityStatusHiddenLocked();
+
+    void requestClientSessionLocked(ClientState cs) {
+        if (!cs.sessionRequested) {
+            if (DEBUG) Slog.v(TAG, "Creating new session for client " + cs);
+            InputChannel[] channels = InputChannel.openInputChannelPair(cs.toString());
+            cs.sessionRequested = true;
+            executeOrSendMessage(mCurMethod, mCaller.obtainMessageOOO(
+                    MSG_CREATE_SESSION, mCurMethod, channels[1],
+                    new MethodCallback(this, mCurMethod, channels[0])));
+        }
+    }
+
+    void clearClientSessionLocked(ClientState cs) {
+        finishSessionLocked(cs.curSession);
+        cs.curSession = null;
+        cs.sessionRequested = false;
+    }
+
+    private void finishSessionLocked(SessionState sessionState) {
+        if (sessionState != null) {
+            if (sessionState.session != null) {
+                try {
+                    sessionState.session.finishSession();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Session failed to close due to remote exception", e);
+                    setImeWindowVisibilityStatusHiddenLocked();
+                }
+                sessionState.session = null;
+            }
+            if (sessionState.channel != null) {
+                sessionState.channel.dispose();
+                sessionState.channel = null;
             }
         }
     }
@@ -1322,12 +1353,10 @@
     void clearCurMethodLocked() {
         if (mCurMethod != null) {
             for (ClientState cs : mClients.values()) {
-                cs.sessionRequested = false;
-                finishSession(cs.curSession);
-                cs.curSession = null;
+                clearClientSessionLocked(cs);
             }
 
-            finishSession(mEnabledSession);
+            finishSessionLocked(mEnabledSession);
             mEnabledSession = null;
             mCurMethod = null;
         }
@@ -1570,7 +1599,8 @@
                             == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                         mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
                                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
-                                PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId());
+                                PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),
+                                mContext.getBasePackageName());
                     }
                 } catch (RemoteException e) {
                 }
@@ -1713,6 +1743,7 @@
 
         boolean res = false;
         if (mCurMethod != null) {
+            if (DEBUG) Slog.d(TAG, "showCurrentInputLocked: mCurToken=" + mCurToken);
             executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
                     MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
                     resultReceiver));
@@ -1784,13 +1815,11 @@
     boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
         if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
                 && (mShowExplicitlyRequested || mShowForced)) {
-            if (DEBUG) Slog.v(TAG,
-                    "Not hiding: explicit show not cancelled by non-explicit hide");
+            if (DEBUG) Slog.v(TAG, "Not hiding: explicit show not cancelled by non-explicit hide");
             return false;
         }
         if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
-            if (DEBUG) Slog.v(TAG,
-                    "Not hiding: forced show not cancelled by not-always hide");
+            if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide");
             return false;
         }
         boolean res;
@@ -2301,8 +2330,9 @@
             case MSG_SHOW_SOFT_INPUT:
                 args = (SomeArgs)msg.obj;
                 try {
-                    ((IInputMethod)args.arg1).showSoftInput(msg.arg1,
-                            (ResultReceiver)args.arg2);
+                    if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".showSoftInput("
+                            + msg.arg1 + ", " + args.arg2 + ")");
+                    ((IInputMethod)args.arg1).showSoftInput(msg.arg1, (ResultReceiver)args.arg2);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -2310,8 +2340,9 @@
             case MSG_HIDE_SOFT_INPUT:
                 args = (SomeArgs)msg.obj;
                 try {
-                    ((IInputMethod)args.arg1).hideSoftInput(0,
-                            (ResultReceiver)args.arg2);
+                    if (DEBUG) Slog.v(TAG, "Calling " + args.arg1 + ".hideSoftInput(0, "
+                            + args.arg2 + ")");
+                    ((IInputMethod)args.arg1).hideSoftInput(0, (ResultReceiver)args.arg2);
                 } catch (RemoteException e) {
                 }
                 args.recycle();
@@ -2325,15 +2356,23 @@
                 }
                 args.recycle();
                 return true;
-            case MSG_CREATE_SESSION:
+            case MSG_CREATE_SESSION: {
                 args = (SomeArgs)msg.obj;
+                IInputMethod method = (IInputMethod)args.arg1;
+                InputChannel channel = (InputChannel)args.arg2;
                 try {
-                    ((IInputMethod)args.arg1).createSession(
-                            (IInputMethodCallback)args.arg2);
+                    method.createSession(channel, (IInputSessionCallback)args.arg3);
                 } catch (RemoteException e) {
+                } finally {
+                    // Dispose the channel if the input method is not local to this process
+                    // because the remote proxy will get its own copy when unparceled.
+                    if (channel != null && Binder.isProxy(method)) {
+                        channel.dispose();
+                    }
                 }
                 args.recycle();
                 return true;
+            }
             // ---------------------------------------------------------
 
             case MSG_START_INPUT:
@@ -2368,16 +2407,24 @@
                     // There is nothing interesting about the last client dying.
                 }
                 return true;
-            case MSG_BIND_METHOD:
+            case MSG_BIND_METHOD: {
                 args = (SomeArgs)msg.obj;
+                IInputMethodClient client = (IInputMethodClient)args.arg1;
+                InputBindResult res = (InputBindResult)args.arg2;
                 try {
-                    ((IInputMethodClient)args.arg1).onBindMethod(
-                            (InputBindResult)args.arg2);
+                    client.onBindMethod(res);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Client died receiving input method " + args.arg2);
+                } finally {
+                    // Dispose the channel if the input method is not local to this process
+                    // because the remote proxy will get its own copy when unparceled.
+                    if (res.channel != null && Binder.isProxy(client)) {
+                        res.channel.dispose();
+                    }
                 }
                 args.recycle();
                 return true;
+            }
             case MSG_SET_ACTIVE:
                 try {
                     ((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 9b19008..35345f5 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -117,7 +117,7 @@
             boolean printedHeader = false;
             F filter;
             for (int i=0; i<N && (filter=a[i]) != null; i++) {
-                if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+                if (packageName != null && !isPackageForFilter(packageName, filter)) {
                     continue;
                 }
                 if (title != null) {
@@ -357,11 +357,11 @@
     }
 
     /**
-     * Return the package that owns this filter.  This must be implemented to
-     * provide correct filtering of Intents that have specified a package name
-     * they are to be delivered to.
+     * Returns whether this filter is owned by this package. This must be
+     * implemented to provide correct filtering of Intents that have
+     * specified a package name they are to be delivered to.
      */
-    protected abstract String packageForFilter(F filter);
+    protected abstract boolean isPackageForFilter(String packageName, F filter);
 
     protected abstract F[] newArray(int size);
 
@@ -556,7 +556,7 @@
             }
 
             // Is delivery being limited to filters owned by a particular package?
-            if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+            if (packageName != null && !isPackageForFilter(packageName, filter)) {
                 if (debug) {
                     Slog.v(TAG, "  Filter is not from package " + packageName + "; skipping");
                 }
@@ -710,8 +710,8 @@
     }
 
     private final IntentResolverOld<F, R> mOldResolver = new IntentResolverOld<F, R>() {
-        @Override protected String packageForFilter(F filter) {
-            return IntentResolver.this.packageForFilter(filter);
+        @Override protected boolean isPackageForFilter(String packageName, F filter) {
+            return IntentResolver.this.isPackageForFilter(packageName, filter);
         }
         @Override protected boolean allowFilterResult(F filter, List<R> dest) {
             return IntentResolver.this.allowFilterResult(filter, dest);
diff --git a/services/java/com/android/server/IntentResolverOld.java b/services/java/com/android/server/IntentResolverOld.java
index 4dd77ce..94a2379 100644
--- a/services/java/com/android/server/IntentResolverOld.java
+++ b/services/java/com/android/server/IntentResolverOld.java
@@ -106,7 +106,7 @@
             boolean printedHeader = false;
             for (int i=0; i<N; i++) {
                 F filter = a.get(i);
-                if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+                if (packageName != null && !isPackageForFilter(packageName, filter)) {
                     continue;
                 }
                 if (title != null) {
@@ -336,11 +336,11 @@
     }
 
     /**
-     * Return the package that owns this filter.  This must be implemented to
-     * provide correct filtering of Intents that have specified a package name
-     * they are to be delivered to.
+     * Returns whether this filter is owned by this package. This must be
+     * implemented to provide correct filtering of Intents that have
+     * specified a package name they are to be delivered to.
      */
-    protected abstract String packageForFilter(F filter);
+    protected abstract boolean isPackageForFilter(String packageName, F filter);
     
     @SuppressWarnings("unchecked")
     protected R newResult(F filter, int match, int userId) {
@@ -529,7 +529,7 @@
             }
 
             // Is delivery being limited to filters owned by a particular package?
-            if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+            if (packageName != null && !isPackageForFilter(packageName, filter)) {
                 if (debug) {
                     Slog.v(TAG, "  Filter is not from package " + packageName + "; skipping");
                 }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bcb7cb7..1e1cf5a 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -54,19 +54,17 @@
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.Slog;
-
-import com.android.internal.app.IAppOpsService;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
 import com.android.server.location.GeocoderProxy;
+import com.android.server.location.GeofenceProxy;
 import com.android.server.location.GeofenceManager;
 import com.android.server.location.GpsLocationProvider;
 import com.android.server.location.LocationBlacklist;
@@ -338,11 +336,11 @@
         addProviderLocked(passiveProvider);
         mEnabledProviders.add(passiveProvider.getName());
         mPassiveProvider = passiveProvider;
+        // Create a gps location provider
+        GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
+                mLocationHandler.getLooper());
 
         if (GpsLocationProvider.isSupported()) {
-            // Create a gps location provider
-            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this,
-                    mLocationHandler.getLooper());
             mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
             mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
             addProviderLocked(gpsProvider);
@@ -406,6 +404,14 @@
         if (mGeocodeProvider == null) {
             Slog.e(TAG,  "no geocoder provider found");
         }
+
+        // bind to geofence provider
+        GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, providerPackageNames,
+                mLocationHandler, gpsProvider.getGpsGeofenceProxy());
+        if (provider == null) {
+            Slog.e(TAG,  "no geofence provider found");
+        }
+
     }
 
     /**
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 2e0c977..e8d7882 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -596,6 +596,26 @@
         }
     };
 
+    private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            waitForReady();
+            String action = intent.getAction();
+            // Since fstrim will be run on a daily basis we do not expect
+            // fstrim to be too long, so it is not interruptible. We will
+            // implement interruption only in case we see issues.
+            if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
+                try {
+                    // This method runs on the handler thread,
+                    // so it is safe to directly call into vold.
+                    mConnector.execute("fstrim", "dotrim");
+                } catch (NativeDaemonConnectorException ndce) {
+                    Slog.e(TAG, "Failed to run fstrim!");
+                }
+            }
+        }
+    };
+
     private final class MountServiceBinderListener implements IBinder.DeathRecipient {
         final IMountServiceListener mListener;
 
@@ -1301,6 +1321,12 @@
                     mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
         }
 
+        // Watch for idle maintenance changes
+        IntentFilter idleMaintenanceFilter = new IntentFilter();
+        idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
+        mContext.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
+                idleMaintenanceFilter, null, mHandler);
+
         // Add OBB Action Handler to MountService thread.
         mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
 
@@ -1577,7 +1603,7 @@
             boolean mounted = false;
             try {
                 mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath()));
-            } catch (IllegalStateException e) {
+            } catch (IllegalArgumentException e) {
             }
 
             if (!mounted) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 7686705..d2acb40 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -233,6 +233,7 @@
             try {
                 mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
             } catch (RemoteException e) {
+            } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
@@ -248,6 +249,7 @@
             try {
                 mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
             } catch (RemoteException e) {
+            } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
@@ -262,6 +264,7 @@
             try {
                 mObservers.getBroadcastItem(i).interfaceAdded(iface);
             } catch (RemoteException e) {
+            } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
@@ -281,6 +284,7 @@
             try {
                 mObservers.getBroadcastItem(i).interfaceRemoved(iface);
             } catch (RemoteException e) {
+            } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
@@ -295,6 +299,7 @@
             try {
                 mObservers.getBroadcastItem(i).limitReached(limitName, iface);
             } catch (RemoteException e) {
+            } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
@@ -309,6 +314,7 @@
             try {
                 mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(label, active);
             } catch (RemoteException e) {
+            } catch (RuntimeException e) {
             }
         }
         mObservers.finishBroadcast();
@@ -833,33 +839,6 @@
         return event.getMessage().endsWith("started");
     }
 
-    // TODO(BT) Remove
-    @Override
-    public void startReverseTethering(String iface) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        // cmd is "tether start first_start first_stop second_start second_stop ..."
-        // an odd number of addrs will fail
-        try {
-            mConnector.execute("tether", "start-reverse", iface);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-        BluetoothTetheringDataTracker.getInstance().startReverseTether(iface);
-
-    }
-
-    // TODO(BT) Remove
-    @Override
-    public void stopReverseTethering() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("tether", "stop-reverse");
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-        BluetoothTetheringDataTracker.getInstance().stopReverseTether();
-    }
-
     @Override
     public void tetherInterface(String iface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 9f2685b..cfb892f 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -26,16 +26,17 @@
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
-import android.app.INotificationListener;
 import android.app.ITransientNotification;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -50,14 +51,16 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.service.notification.INotificationListener;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AtomicFile;
@@ -69,8 +72,6 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
 
-import com.android.internal.statusbar.StatusBarNotification;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -122,8 +123,11 @@
     private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
     private static final boolean ENABLE_BLOCKED_TOASTS = true;
 
+    private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
+
     final Context mContext;
     final IActivityManager mAm;
+    final UserManager mUserManager;
     final IBinder mForegroundToken = new Binder();
 
     private WorkerHandler mHandler;
@@ -163,7 +167,18 @@
 
     private final AppOpsManager mAppOps;
 
-    private ArrayList<NotificationListenerInfo> mListeners = new ArrayList<NotificationListenerInfo>();
+    // contains connections to all connected listeners, including app services
+    // and system listeners
+    private ArrayList<NotificationListenerInfo> mListeners
+            = new ArrayList<NotificationListenerInfo>();
+    // things that will be put into mListeners as soon as they're ready
+    private ArrayList<String> mServicesBinding = new ArrayList<String>();
+    // lists the component names of all enabled (and therefore connected) listener
+    // app services for the current user only
+    private HashSet<ComponentName> mEnabledListenersForCurrentUser
+            = new HashSet<ComponentName>();
+    // Just the packages from mEnabledListenersForCurrentUser
+    private HashSet<String> mEnabledListenerPackageNames = new HashSet<String>();
 
     // Notification control database. For now just contains disabled packages.
     private AtomicFile mPolicyFile;
@@ -180,14 +195,42 @@
 
     private class NotificationListenerInfo implements DeathRecipient {
         INotificationListener listener;
+        ComponentName component;
         int userid;
-        public NotificationListenerInfo(INotificationListener listener, int userid) {
+        boolean isSystem;
+        ServiceConnection connection;
+
+        public NotificationListenerInfo(INotificationListener listener, ComponentName component,
+                int userid, boolean isSystem) {
             this.listener = listener;
+            this.component = component;
             this.userid = userid;
+            this.isSystem = isSystem;
+            this.connection = null;
+        }
+
+        public NotificationListenerInfo(INotificationListener listener, ComponentName component,
+                int userid, ServiceConnection connection) {
+            this.listener = listener;
+            this.component = component;
+            this.userid = userid;
+            this.isSystem = false;
+            this.connection = connection;
+        }
+
+        boolean enabledAndUserMatches(StatusBarNotification sbn) {
+            final int nid = sbn.getUserId();
+            if (!isEnabledForCurrentUser()) {
+                return false;
+            }
+            if (this.userid == UserHandle.USER_ALL) return true;
+            return (nid == UserHandle.USER_ALL || nid == this.userid);
         }
 
         public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
-            if (this.userid != sbn.getUserId()) return;
+            if (!enabledAndUserMatches(sbn)) {
+                return;
+            }
             try {
                 listener.onNotificationPosted(sbn);
             } catch (RemoteException ex) {
@@ -196,7 +239,7 @@
         }
 
         public void notifyRemovedIfUserMatch(StatusBarNotification sbn) {
-            if (this.userid != sbn.getUserId()) return;
+            if (!enabledAndUserMatches(sbn)) return;
             try {
                 listener.onNotificationRemoved(sbn);
             } catch (RemoteException ex) {
@@ -206,7 +249,17 @@
 
         @Override
         public void binderDied() {
-            unregisterListener(this.listener, this.userid);
+            if (connection == null) {
+                // This is not a service; it won't be recreated. We can give up this connection.
+                unregisterListener(this.listener, this.userid);
+            }
+        }
+
+        /** convenience method for looking in mEnabledListenersForCurrentUser */
+        public boolean isEnabledForCurrentUser() {
+            if (this.isSystem) return true;
+            if (this.connection == null) return false;
+            return mEnabledListenersForCurrentUser.contains(this.component);
         }
     }
 
@@ -215,9 +268,15 @@
         ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
 
         public Archive() {
-
         }
+
         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;
+
             if (mBuffer.size() == BUFFER_SIZE) {
                 mBuffer.removeFirst();
             }
@@ -406,13 +465,21 @@
         }
     }
 
+    /**
+     * System-only API for getting a list of current (i.e. not cleared) notifications.
+     *
+     * Requires ACCESS_NOTIFICATIONS which is signature|system.
+     */
+    @Override
     public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+        // enforce() will ensure the calling uid has the correct permission
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
                 "NotificationManagerService.getActiveNotifications");
 
         StatusBarNotification[] tmp = null;
         int uid = Binder.getCallingUid();
 
+        // noteOp will check to make sure the callingPkg matches the uid
         if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
                 == AppOpsManager.MODE_ALLOWED) {
             synchronized (mNotificationList) {
@@ -426,13 +493,21 @@
         return tmp;
     }
 
+    /**
+     * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+     *
+     * Requires ACCESS_NOTIFICATIONS which is signature|system.
+     */
+    @Override
     public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+        // enforce() will ensure the calling uid has the correct permission
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
                 "NotificationManagerService.getHistoricalNotifications");
 
         StatusBarNotification[] tmp = null;
         int uid = Binder.getCallingUid();
 
+        // noteOp will check to make sure the callingPkg matches the uid
         if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
                 == AppOpsManager.MODE_ALLOWED) {
             synchronized (mArchive) {
@@ -442,12 +517,76 @@
         return tmp;
     }
 
+    /**
+     * Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS
+     * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
+     */
+    void rebindListenerServices() {
+        String flat = Settings.Secure.getString(
+                mContext.getContentResolver(),
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
+        NotificationListenerInfo[] toRemove = new NotificationListenerInfo[mListeners.size()];
+        final ArrayList<ComponentName> toAdd;
+        final int currentUser = ActivityManager.getCurrentUser();
+
+        synchronized (mNotificationList) {
+            // unbind and remove all existing listeners
+            toRemove = mListeners.toArray(toRemove);
+
+            toAdd = new ArrayList<ComponentName>();
+            final HashSet<ComponentName> newEnabled = new HashSet<ComponentName>();
+            final HashSet<String> newPackages = new HashSet<String>();
+
+            // decode the list of components
+            if (flat != null) {
+                String[] components = flat.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
+                for (int i=0; i<components.length; i++) {
+                    final ComponentName component
+                            = ComponentName.unflattenFromString(components[i]);
+                    if (component != null) {
+                        newEnabled.add(component);
+                        toAdd.add(component);
+                        newPackages.add(component.getPackageName());
+                    }
+                }
+
+                mEnabledListenersForCurrentUser = newEnabled;
+                mEnabledListenerPackageNames = newPackages;
+            }
+        }
+
+        for (NotificationListenerInfo info : toRemove) {
+            final ComponentName component = info.component;
+            final int oldUser = info.userid;
+            Slog.v(TAG, "disabling notification listener for user " + oldUser + ": " + component);
+            unregisterListenerService(component, info.userid);
+        }
+
+        final int N = toAdd.size();
+        for (int i=0; i<N; i++) {
+            final ComponentName component = toAdd.get(i);
+            Slog.v(TAG, "enabling notification listener for user " + currentUser + ": "
+                    + component);
+            registerListenerService(component, currentUser);
+        }
+    }
+
+    /**
+     * Register a listener binder directly with the notification manager.
+     *
+     * Only works with system callers. Apps should extend
+     * {@link android.service.notification.NotificationListenerService}.
+     */
     @Override
-    public void registerListener(final INotificationListener listener, final int userid) {
+    public void registerListener(final INotificationListener listener,
+            final ComponentName component, final int userid) {
         checkCallerIsSystem();
+
         synchronized (mNotificationList) {
             try {
-                NotificationListenerInfo info = new NotificationListenerInfo(listener, userid);
+                NotificationListenerInfo info
+                        = new NotificationListenerInfo(listener, component, userid, true);
                 listener.asBinder().linkToDeath(info, 0);
                 mListeners.add(info);
             } catch (RemoteException e) {
@@ -456,20 +595,133 @@
         }
     }
 
+    /**
+     * Version of registerListener that takes the name of a
+     * {@link android.service.notification.NotificationListenerService} to bind to.
+     *
+     * This is the mechanism by which third parties may subscribe to notifications.
+     */
+    private void registerListenerService(final ComponentName name, final int userid) {
+        checkCallerIsSystem();
+
+        if (DBG) Slog.v(TAG, "registerListenerService: " + name + " u=" + userid);
+
+        synchronized (mNotificationList) {
+            final String servicesBindingTag = name.toString() + "/" + userid;
+            if (mServicesBinding.contains(servicesBindingTag)) {
+                // stop registering this thing already! we're working on it
+                return;
+            }
+            mServicesBinding.add(servicesBindingTag);
+
+            final int N = mListeners.size();
+            for (int i=N-1; i>=0; i--) {
+                final NotificationListenerInfo info = mListeners.get(i);
+                if (name.equals(info.component)
+                        && info.userid == userid) {
+                    // cut old connections
+                    if (DBG) Slog.v(TAG, "    disconnecting old listener: " + info.listener);
+                    mListeners.remove(i);
+                    if (info.connection != null) {
+                        mContext.unbindService(info.connection);
+                    }
+                }
+            }
+
+            Intent intent = new Intent(NotificationListenerService.SERVICE_INTERFACE);
+            intent.setComponent(name);
+
+            intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+                    com.android.internal.R.string.notification_listener_binding_label);
+            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+                    mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
+
+            try {
+                if (DBG) Slog.v(TAG, "binding: " + intent);
+                if (!mContext.bindServiceAsUser(intent,
+                        new ServiceConnection() {
+                            INotificationListener mListener;
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder service) {
+                                synchronized (mNotificationList) {
+                                    mServicesBinding.remove(servicesBindingTag);
+                                    try {
+                                        mListener = INotificationListener.Stub.asInterface(service);
+                                        NotificationListenerInfo info = new NotificationListenerInfo(
+                                                mListener, name, userid, this);
+                                        service.linkToDeath(info, 0);
+                                        mListeners.add(info);
+                                    } catch (RemoteException e) {
+                                        // already dead
+                                    }
+                                }
+                            }
+
+                            @Override
+                            public void onServiceDisconnected(ComponentName name) {
+                                Slog.v(TAG, "notification listener connection lost: " + name);
+                            }
+                        },
+                        Context.BIND_AUTO_CREATE,
+                        new UserHandle(userid)))
+                {
+                    mServicesBinding.remove(servicesBindingTag);
+                    Slog.w(TAG, "Unable to bind listener service: " + intent);
+                    return;
+                }
+            } catch (SecurityException ex) {
+                Slog.e(TAG, "Unable to bind listener service: " + intent, ex);
+                return;
+            }
+        }
+    }
+
+    /**
+     * Remove a listener binder directly
+     */
     @Override
     public void unregisterListener(INotificationListener listener, int userid) {
-        checkCallerIsSystem();
+        // no need to check permissions; if your listener binder is in the list,
+        // that's proof that you had permission to add it in the first place
+
         synchronized (mNotificationList) {
             final int N = mListeners.size();
             for (int i=N-1; i>=0; i--) {
                 final NotificationListenerInfo info = mListeners.get(i);
                 if (info.listener == listener && info.userid == userid) {
-                    mListeners.remove(listener);
+                    mListeners.remove(i);
+                    if (info.connection != null) {
+                        mContext.unbindService(info.connection);
+                    }
                 }
             }
         }
     }
 
+    /**
+     * Remove a listener service for the given user by ComponentName
+     */
+    private void unregisterListenerService(ComponentName name, int userid) {
+        checkCallerIsSystem();
+
+        synchronized (mNotificationList) {
+            final int N = mListeners.size();
+            for (int i=N-1; i>=0; i--) {
+                final NotificationListenerInfo info = mListeners.get(i);
+                if (name.equals(info.component)
+                        && info.userid == userid) {
+                    mListeners.remove(i);
+                    if (info.connection != null) {
+                        mContext.unbindService(info.connection);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * asynchronously notify all listeners about a new notification
+     */
     private void notifyPostedLocked(NotificationRecord n) {
         final StatusBarNotification sbn = n.sbn;
         for (final NotificationListenerInfo info : mListeners) {
@@ -481,6 +733,9 @@
         }
     }
 
+    /**
+     * asynchronously notify all listeners about a removed notification
+     */
     private void notifyRemovedLocked(NotificationRecord n) {
         final StatusBarNotification sbn = n.sbn;
         for (final NotificationListenerInfo info : mListeners) {
@@ -492,6 +747,57 @@
         }
     }
 
+    // -- APIs to support listeners clicking/clearing notifications --
+
+    private NotificationListenerInfo checkListenerToken(INotificationListener listener) {
+        final IBinder token = listener.asBinder();
+        final int N = mListeners.size();
+        for (int i=0; i<N; i++) {
+            final NotificationListenerInfo info = mListeners.get(i);
+            if (info.listener.asBinder() == token) return info;
+        }
+        throw new SecurityException("Disallowed call from unknown listener: " + listener);
+    }
+
+    /**
+     * Allow an INotificationListener to simulate a "clear all" operation.
+     *
+     * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
+     *
+     * @param token The binder for the listener, to check that the caller is allowed
+     */
+    public void clearAllNotificationsFromListener(INotificationListener token) {
+        NotificationListenerInfo info = checkListenerToken(token);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            cancelAll(info.userid);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
+     * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+     *
+     * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+     *
+     * @param token The binder for the listener, to check that the caller is allowed
+     */
+    public void clearNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
+        NotificationListenerInfo info = checkListenerToken(token);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            cancelNotification(pkg, tag, id, 0,
+                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                    true,
+                    info.userid);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    // -- end of listener APIs --
+
     public static final class NotificationRecord
     {
         final StatusBarNotification sbn;
@@ -710,12 +1016,23 @@
                     }
                     pkgList = new String[]{pkgName};
                 }
+
+                boolean anyListenersInvolved = false;
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkgName : pkgList) {
                         cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart,
                                 UserHandle.USER_ALL);
+                        if (mEnabledListenerPackageNames.contains(pkgName)) {
+                            anyListenersInvolved = true;
+                        }
                     }
                 }
+
+                if (anyListenersInvolved) {
+                    // make sure we're still bound to any of our
+                    // listeners who may have just upgraded
+                    rebindListenerServices();
+                }
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 // Keep track of screen on/off state, but do not turn off the notification light
                 // until user passes through the lock screen or views the notification.
@@ -734,37 +1051,55 @@
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
                 mNotificationLight.turnOff();
+            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
+                // reload per-user settings
+                mSettingsObserver.update(null);
             }
         }
     };
 
     class SettingsObserver extends ContentObserver {
+        private final Uri NOTIFICATION_LIGHT_PULSE_URI
+                = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
+
+        private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
+                = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+
         SettingsObserver(Handler handler) {
             super(handler);
         }
 
         void observe() {
             ContentResolver resolver = mContext.getContentResolver();
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
-            update();
+            resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
+                    false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
+                    false, this, UserHandle.USER_ALL);
+            update(null);
         }
 
-        @Override public void onChange(boolean selfChange) {
-            update();
+        @Override public void onChange(boolean selfChange, Uri uri) {
+            update(uri);
         }
 
-        public void update() {
+        public void update(Uri uri) {
             ContentResolver resolver = mContext.getContentResolver();
-            boolean pulseEnabled = Settings.System.getInt(resolver,
-                        Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
-            if (mNotificationPulseEnabled != pulseEnabled) {
-                mNotificationPulseEnabled = pulseEnabled;
-                updateNotificationPulse();
+            if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
+                boolean pulseEnabled = Settings.System.getInt(resolver,
+                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
+                if (mNotificationPulseEnabled != pulseEnabled) {
+                    mNotificationPulseEnabled = pulseEnabled;
+                    updateNotificationPulse();
+                }
+            }
+            if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
+                rebindListenerServices();
             }
         }
     }
 
+    private SettingsObserver mSettingsObserver;
+
     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
         int[] ar = r.getIntArray(resid);
         if (ar == null) {
@@ -785,6 +1120,7 @@
         mContext = context;
         mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mAm = ActivityManagerNative.getDefault();
+        mUserManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
         mToastQueue = new ArrayList<ToastRecord>();
         mHandler = new WorkerHandler();
 
@@ -832,6 +1168,7 @@
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(Intent.ACTION_USER_PRESENT);
         filter.addAction(Intent.ACTION_USER_STOPPED);
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mIntentReceiver, filter);
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -843,8 +1180,8 @@
         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         mContext.registerReceiver(mIntentReceiver, sdFilter);
 
-        SettingsObserver observer = new SettingsObserver(mHandler);
-        observer.observe();
+        mSettingsObserver = new SettingsObserver(mHandler);
+        mSettingsObserver.observe();
     }
 
     /**
@@ -875,6 +1212,9 @@
 
         // no beeping until we're basically done booting
         mSystemReady = true;
+
+        // make sure our listener services are properly bound
+        rebindListenerServices();
     }
 
     // Toasts
@@ -1249,9 +1589,6 @@
                     sendAccessibilityEvent(notification, pkg);
                 }
 
-                // finally, keep some of this information around for later use
-                mArchive.record(n);
-
                 notifyPostedLocked(r);
             } else {
                 Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
@@ -1466,6 +1803,9 @@
         if (mLedNotification == r) {
             mLedNotification = null;
         }
+
+        // Save it for users of getHistoricalNotifications()
+        mArchive.record(r.sbn);
     }
 
     /**
@@ -1700,6 +2040,19 @@
 
         pw.println("Current Notification Manager state:");
 
+        pw.println("  Listeners (" + mEnabledListenersForCurrentUser.size()
+                + ") enabled for current user:");
+        for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
+            pw.println("    " + cmpt);
+        }
+
+        pw.println("  Live listeners (" + mListeners.size() + "):");
+        for (NotificationListenerInfo info : mListeners) {
+            pw.println("    " + info.component
+                    + " (user " + info.userid + "): " + info.listener
+                    + (info.isSystem?" SYSTEM":""));
+        }
+
         int N;
 
         synchronized (mToastQueue) {
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 1fe98af..c21d8c6 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.StatusBarManager;
+import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -33,7 +34,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.statusbar.StatusBarNotification;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4631395..a30fc3b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -862,6 +862,11 @@
             public void run() {
                 Slog.i(TAG, "Making services ready");
 
+                try {
+                    ActivityManagerService.self().startObservingNativeCrashes();
+                } catch (Throwable e) {
+                    reportWtf("observing native crashes", e);
+                }
                 if (!headless) startSystemUi(contextF);
                 try {
                     if (mountServiceF != null) mountServiceF.systemReady();
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index b2a8ad8..167e7af 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -29,6 +29,7 @@
 import android.os.BatteryManager;
 import android.os.Debug;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.ServiceManager;
@@ -87,7 +88,6 @@
     AlarmManagerService mAlarm;
     ActivityManagerService mActivity;
     boolean mCompleted;
-    boolean mForceKillSystem;
     Monitor mCurrentMonitor;
 
     int mPhonePid;
@@ -114,6 +114,10 @@
      * Used for scheduling monitor callbacks and checking memory usage.
      */
     final class HeartbeatHandler extends Handler {
+        HeartbeatHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -130,7 +134,9 @@
 
                     final int size = mMonitors.size();
                     for (int i = 0 ; i < size ; i++) {
-                        mCurrentMonitor = mMonitors.get(i);
+                        synchronized (Watchdog.this) {
+                            mCurrentMonitor = mMonitors.get(i);
+                        }
                         mCurrentMonitor.monitor();
                     }
 
@@ -183,7 +189,9 @@
 
     private Watchdog() {
         super("watchdog");
-        mHandler = new HeartbeatHandler();
+        // Explicitly bind the HeartbeatHandler to run on the ServerThread, so
+        // that it can't get accidentally bound to another thread.
+        mHandler = new HeartbeatHandler(Looper.getMainLooper());
     }
 
     public void init(Context context, BatteryService battery,
@@ -381,6 +389,8 @@
             mCompleted = false;
             mHandler.sendEmptyMessage(MONITOR);
 
+
+            final String name;
             synchronized (this) {
                 long timeout = TIME_TO_WAIT;
 
@@ -389,16 +399,16 @@
                 // to timeout on is asleep as well and won't have a chance to run, causing a false
                 // positive on when to kill things.
                 long start = SystemClock.uptimeMillis();
-                while (timeout > 0 && !mForceKillSystem) {
+                while (timeout > 0) {
                     try {
-                        wait(timeout);  // notifyAll() is called when mForceKillSystem is set
+                        wait(timeout);
                     } catch (InterruptedException e) {
                         Log.wtf(TAG, e);
                     }
                     timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
                 }
 
-                if (mCompleted && !mForceKillSystem) {
+                if (mCompleted) {
                     // The monitors have returned.
                     waitedHalf = false;
                     continue;
@@ -414,14 +424,14 @@
                     waitedHalf = true;
                     continue;
                 }
+
+                name = (mCurrentMonitor != null) ?
+                    mCurrentMonitor.getClass().getName() : "null";
             }
 
             // If we got here, that means that the system is most likely hung.
             // First collect stack traces from all threads of the system process.
             // Then kill this process so that the system will restart.
-
-            final String name = (mCurrentMonitor != null) ?
-                    mCurrentMonitor.getClass().getName() : "null";
             EventLog.writeEvent(EventLogTags.WATCHDOG, name);
 
             ArrayList<Integer> pids = new ArrayList<Integer>();
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index d84018f..527e891 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1070,14 +1070,6 @@
                 if (userState.mBindingServices.contains(componentName)) {
                     continue;
                 }
-                // No enabled installed services => disable accessibility to avoid
-                // sending accessibility events with no recipient across processes.
-                if (userState.mEnabledServices.isEmpty()) {
-                    userState.mIsAccessibilityEnabled = false;
-                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                            Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
-                    return;
-                }
                 if (userState.mEnabledServices.contains(componentName)) {
                     if (service == null) {
                         service = new Service(userState.mUserId, componentName, installedService);
@@ -1098,6 +1090,14 @@
                 }
             }
         }
+
+        // No enabled installed services => disable accessibility to avoid
+        // sending accessibility events with no recipient across processes.
+        if (isEnabled && userState.mEnabledServices.isEmpty()) {
+            userState.mIsAccessibilityEnabled = false;
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
+        }
     }
 
     private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 49295f5..14d808f 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -58,6 +58,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -115,6 +116,7 @@
 
     // Messages that can be sent on mHandler
     private static final int MESSAGE_TIMED_OUT = 3;
+    private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4;
 
     private final IAccountAuthenticatorCache mAuthenticatorCache;
 
@@ -270,7 +272,7 @@
 
     private UserManager getUserManager() {
         if (mUserManager == null) {
-            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            mUserManager = UserManager.get(mContext);
         }
         return mUserManager;
     }
@@ -455,7 +457,6 @@
 
     @Override
     public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
-        Slog.d(TAG, "onServiceChanged() for userId " + userId);
         validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
     }
 
@@ -542,17 +543,22 @@
         }
     }
 
-    public boolean addAccount(Account account, String password, Bundle extras) {
+    @Override
+    public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.v(TAG, "addAccount: " + account
+            Log.v(TAG, "addAccountExplicitly: " + account
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
-        if (!canUserModifyAccounts(Binder.getCallingUid())) {
-            return false;
-        }
+        /*
+         * Child users are not allowed to add accounts. Only the accounts that are
+         * shared by the parent profile can be added to child profile.
+         *
+         * TODO: Only allow accounts that were shared to be added by
+         *     a limited user.
+         */
 
         UserAccounts accounts = getUserAccountsForCaller();
         // fails if the account already exists
@@ -588,17 +594,10 @@
                     if (result != null) {
                         if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                             // Create a Session for the target user and pass in the bundle
-                            Slog.i(TAG, "getAccountCredentialsForCloning returned success, "
-                                    + "sending result to target user");
                             completeCloningAccount(result, account, toAccounts);
-                        } else {
-                            Slog.e(TAG, "getAccountCredentialsForCloning returned failure");
-                            clonePassword(fromAccounts, toAccounts, account);
                         }
                         return;
                     } else {
-                        Slog.e(TAG, "getAccountCredentialsForCloning returned null");
-                        clonePassword(fromAccounts, toAccounts, account);
                         super.onResult(result);
                     }
                 }
@@ -609,23 +608,6 @@
         return true;
     }
 
-    // TODO: Remove fallback - move to authenticator
-    private void clonePassword(UserAccounts fromAccounts, UserAccounts toAccounts,
-            Account account) {
-        long id = clearCallingIdentity();
-        try {
-            String password = readPasswordInternal(fromAccounts, account);
-            String extraFlags = readUserDataInternal(fromAccounts, account, "flags");
-            String extraServices = readUserDataInternal(fromAccounts, account, "services");
-            Bundle extras = new Bundle();
-            extras.putString("flags", extraFlags);
-            extras.putString("services", extraServices);
-            addAccountInternal(toAccounts, account, password, extras, true);
-        } finally {
-            restoreCallingIdentity(id);
-        }
-    }
-
     void completeCloningAccount(final Bundle result, final Account account,
             final UserAccounts targetUser) {
         long id = clearCallingIdentity();
@@ -638,22 +620,29 @@
                 }
 
                 public void run() throws RemoteException {
-                    mAuthenticator.addAccountFromCredentials(this, account, result);
+                    // Confirm that the owner's account still exists before this step.
+                    UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
+                    synchronized (owner.cacheLock) {
+                        Account[] ownerAccounts = getAccounts(UserHandle.USER_OWNER);
+                        for (Account acc : ownerAccounts) {
+                            if (acc.equals(account)) {
+                                mAuthenticator.addAccountFromCredentials(this, account, result);
+                                break;
+                            }
+                        }
+                    }
                 }
 
                 public void onResult(Bundle result) {
                     if (result != null) {
                         if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                             // TODO: Anything?
-                            Slog.i(TAG, "addAccount returned success");
                         } else {
                             // TODO: Show error notification
                             // TODO: Should we remove the shadow account to avoid retries?
-                            Slog.e(TAG, "addAccountFromCredentials returned failure");
                         }
                         return;
                     } else {
-                        Slog.e(TAG, "addAccountFromCredentials returned null");
                         super.onResult(result);
                     }
                 }
@@ -714,7 +703,33 @@
                 db.endTransaction();
             }
             sendAccountsChangedBroadcast(accounts.userId);
-            return true;
+        }
+        if (accounts.userId == UserHandle.USER_OWNER) {
+            addAccountToLimitedUsers(account);
+        }
+        return true;
+    }
+
+    /**
+     * Adds the account to all limited users as shared accounts. If the user is currently
+     * running, then clone the account too.
+     * @param account the account to share with limited users
+     */
+    private void addAccountToLimitedUsers(Account account) {
+        List<UserInfo> users = getUserManager().getUsers();
+        for (UserInfo user : users) {
+            if (user.isRestricted()) {
+                addSharedAccountAsUser(account, user.id);
+                try {
+                    if (ActivityManagerNative.getDefault().isUserRunning(user.id, false)) {
+                        mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
+                                MESSAGE_COPY_SHARED_ACCOUNT, UserHandle.USER_OWNER, user.id,
+                                account));
+                    }
+                } catch (RemoteException re) {
+                    // Shouldn't happen
+                }
+            }
         }
     }
 
@@ -914,6 +929,7 @@
         }
     }
 
+    @Override
     public void invalidateAuthToken(String accountType, String authToken) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "invalidateAuthToken: accountType " + accountType
@@ -1189,7 +1205,7 @@
 
         final int callingUid = getCallingUid();
         clearCallingIdentity();
-        if (callingUid != android.os.Process.SYSTEM_UID) {
+        if (callingUid != Process.SYSTEM_UID) {
             throw new SecurityException("can only call from system");
         }
         UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
@@ -1359,7 +1375,7 @@
         String subtitle = "";
         if (index > 0) {
             title = titleAndSubtitle.substring(0, index);
-            subtitle = titleAndSubtitle.substring(index + 1);            
+            subtitle = titleAndSubtitle.substring(index + 1);
         }
         UserHandle user = new UserHandle(userId);
         n.setLatestEventInfo(mContext, title, subtitle,
@@ -1417,7 +1433,7 @@
         return id;
     }
 
-    public void addAcount(final IAccountManagerResponse response, final String accountType,
+    public void addAccount(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final boolean expectActivityLaunch, final Bundle optionsIn) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1433,6 +1449,16 @@
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         checkManageAccountsPermission();
 
+        // Is user disallowed from modifying accounts?
+        if (!canUserModifyAccounts(Binder.getCallingUid())) {
+            try {
+                response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
+                        "User is not allowed to add an account!");
+            } catch (RemoteException re) {
+            }
+            return;
+        }
+
         UserAccounts accounts = getUserAccountsForCaller();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -1469,7 +1495,7 @@
             int userId) {
         // Only allow the system process to read accounts of other users
         if (userId != UserHandle.getCallingUserId()
-                && Binder.getCallingUid() != android.os.Process.myUid()) {
+                && Binder.getCallingUid() != Process.myUid()) {
             throw new SecurityException("User " + UserHandle.getCallingUserId()
                     + " trying to confirm account credentials for " + userId);
         }
@@ -1573,17 +1599,20 @@
         private volatile Account[] mAccountsOfType = null;
         private volatile ArrayList<Account> mAccountsWithFeatures = null;
         private volatile int mCurrentAccount = 0;
+        private int mCallingUid;
 
         public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
-                IAccountManagerResponse response, String type, String[] features) {
+                IAccountManagerResponse response, String type, String[] features, int callingUid) {
             super(accounts, response, type, false /* expectActivityLaunch */,
                     true /* stripAuthTokenFromResult */);
+            mCallingUid = callingUid;
             mFeatures = features;
         }
 
         public void run() throws RemoteException {
             synchronized (mAccounts.cacheLock) {
-                mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType);
+                mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
+                        null);
             }
             // check whether each account matches the requested features
             mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
@@ -1668,10 +1697,11 @@
     public Account[] getAccounts(int userId) {
         checkReadAccountsPermission();
         UserAccounts accounts = getUserAccounts(userId);
+        int callingUid = Binder.getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
             synchronized (accounts.cacheLock) {
-                return getAccountsFromCacheLocked(accounts, null);
+                return getAccountsFromCacheLocked(accounts, null, callingUid, null);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -1711,7 +1741,8 @@
                 UserAccounts userAccounts = getUserAccounts(userId);
                 if (userAccounts == null) continue;
                 synchronized (userAccounts.cacheLock) {
-                    Account[] accounts = getAccountsFromCacheLocked(userAccounts, null);
+                    Account[] accounts = getAccountsFromCacheLocked(userAccounts, null,
+                            Binder.getCallingUid(), null);
                     for (int a = 0; a < accounts.length; a++) {
                         runningAccounts.add(new AccountAndUser(accounts[a], userId));
                     }
@@ -1725,9 +1756,15 @@
 
     @Override
     public Account[] getAccountsAsUser(String type, int userId) {
+        return getAccountsAsUser(type, userId, null, -1);
+    }
+
+    private Account[] getAccountsAsUser(String type, int userId, String callingPackage,
+            int packageUid) {
+        int callingUid = Binder.getCallingUid();
         // Only allow the system process to read accounts of other users
         if (userId != UserHandle.getCallingUserId()
-                && Binder.getCallingUid() != android.os.Process.myUid()) {
+                && callingUid != Process.myUid()) {
             throw new SecurityException("User " + UserHandle.getCallingUserId()
                     + " trying to get account for " + userId);
         }
@@ -1737,12 +1774,17 @@
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
+        // If the original calling app was using the framework account chooser activity, we'll
+        // be passed in the original caller's uid here, which is what should be used for filtering.
+        if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
+            callingUid = packageUid;
+        }
         checkReadAccountsPermission();
         UserAccounts accounts = getUserAccounts(userId);
         long identityToken = clearCallingIdentity();
         try {
             synchronized (accounts.cacheLock) {
-                return getAccountsFromCacheLocked(accounts, type);
+                return getAccountsFromCacheLocked(accounts, type, callingUid, callingPackage);
             }
         } finally {
             restoreCallingIdentity(identityToken);
@@ -1813,6 +1855,16 @@
         return getAccountsAsUser(type, UserHandle.getCallingUserId());
     }
 
+    @Override
+    public Account[] getAccountsForPackage(String packageName, int uid) {
+        int callingUid = Binder.getCallingUid();
+        if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
+            throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
+                    + callingUid + " with uid=" + uid);
+        }
+        return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid);
+    }
+
     public void getAccountsByFeatures(IAccountManagerResponse response,
             String type, String[] features) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1826,19 +1878,21 @@
         if (type == null) throw new IllegalArgumentException("accountType is null");
         checkReadAccountsPermission();
         UserAccounts userAccounts = getUserAccountsForCaller();
+        int callingUid = Binder.getCallingUid();
         long identityToken = clearCallingIdentity();
         try {
             if (features == null || features.length == 0) {
                 Account[] accounts;
                 synchronized (userAccounts.cacheLock) {
-                    accounts = getAccountsFromCacheLocked(userAccounts, type);
+                    accounts = getAccountsFromCacheLocked(userAccounts, type, callingUid, null);
                 }
                 Bundle result = new Bundle();
                 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
                 onResult(response, result);
                 return;
             }
-            new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features).bind();
+            new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features,
+                    callingUid).bind();
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -2144,6 +2198,10 @@
                     session.onTimedOut();
                     break;
 
+                case MESSAGE_COPY_SHARED_ACCOUNT:
+                    copyAccountToUser((Account) msg.obj, msg.arg1, msg.arg2);
+                    break;
+
                 default:
                     throw new IllegalStateException("unhandled message: " + msg.what);
             }
@@ -2352,7 +2410,8 @@
                     }
                 }
             } else {
-                Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */);
+                Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
+                        Process.myUid(), null);
                 fout.println("Accounts: " + accounts.length);
                 for (Account account : accounts) {
                     fout.println("  " + account);
@@ -2505,7 +2564,7 @@
 
     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
             int callerUid) {
-        if (callerUid == android.os.Process.SYSTEM_UID) {
+        if (callerUid == Process.SYSTEM_UID) {
             return true;
         }
         UserAccounts accounts = getUserAccountsForCaller();
@@ -2558,10 +2617,10 @@
     }
 
     private boolean canUserModifyAccounts(int callingUid) {
-        if (callingUid != android.os.Process.myUid()) {
-            Bundle restrictions = getUserManager().getUserRestrictions(
-                    new UserHandle(UserHandle.getUserId(callingUid)));
-            if (!restrictions.getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) {
+        if (callingUid != Process.myUid()) {
+            if (getUserManager().getUserRestrictions(
+                    new UserHandle(UserHandle.getUserId(callingUid)))
+                    .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
                 return false;
             }
         }
@@ -2572,7 +2631,7 @@
             throws RemoteException {
         final int callingUid = getCallingUid();
 
-        if (callingUid != android.os.Process.SYSTEM_UID) {
+        if (callingUid != Process.SYSTEM_UID) {
             throw new SecurityException();
         }
 
@@ -2691,13 +2750,78 @@
         accounts.accountCache.put(account.type, newAccountsForType);
     }
 
-    protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType) {
+    private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
+            int callingUid, String callingPackage) {
+        if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
+                || callingUid == Process.myUid()) {
+            return unfiltered;
+        }
+        if (mUserManager.getUserInfo(userAccounts.userId).isRestricted()) {
+            String[] packages = mPackageManager.getPackagesForUid(callingUid);
+            // If any of the packages is a white listed package, return the full set,
+            // otherwise return non-shared accounts only.
+            // This might be a temporary way to specify a whitelist
+            String whiteList = mContext.getResources().getString(
+                    com.android.internal.R.string.config_appsAuthorizedForSharedAccounts);
+            for (String packageName : packages) {
+                if (whiteList.contains(";" + packageName + ";")) {
+                    return unfiltered;
+                }
+            }
+            ArrayList<Account> allowed = new ArrayList<Account>();
+            Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
+            if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered;
+            String requiredAccountType = "";
+            try {
+                for (String packageName : packages) {
+                    PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
+                    if (pi != null && pi.restrictedAccountType != null) {
+                        requiredAccountType = pi.restrictedAccountType;
+                        // If it matches the package name of the original caller, use this choice.
+                        if (callingPackage != null && packageName.equals(callingPackage)) {
+                            break;
+                        }
+                    }
+                }
+            } catch (NameNotFoundException nnfe) {
+            }
+            for (Account account : unfiltered) {
+                if (account.type.equals(requiredAccountType)) {
+                    allowed.add(account);
+                } else {
+                    boolean found = false;
+                    for (Account shared : sharedAccounts) {
+                        if (shared.equals(account)) {
+                            found = true;
+                            break;
+                        }
+                    }
+                    if (!found) {
+                        allowed.add(account);
+                    }
+                }
+            }
+            Account[] filtered = new Account[allowed.size()];
+            allowed.toArray(filtered);
+            return filtered;
+        } else {
+            return unfiltered;
+        }
+    }
+
+    /*
+     * packageName can be null. If not null, it should be used to filter out restricted accounts
+     * that the package is not allowed to access.
+     */
+    protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType,
+            int callingUid, String callingPackage) {
         if (accountType != null) {
             final Account[] accounts = userAccounts.accountCache.get(accountType);
             if (accounts == null) {
                 return EMPTY_ACCOUNT_ARRAY;
             } else {
-                return Arrays.copyOf(accounts, accounts.length);
+                return filterSharedAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
+                        callingUid, callingPackage);
             }
         } else {
             int totalLength = 0;
@@ -2714,7 +2838,7 @@
                         accountsOfType.length);
                 totalLength += accountsOfType.length;
             }
-            return accounts;
+            return filterSharedAccounts(userAccounts, accounts, callingUid, callingPackage);
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d8bcf2cd..cc7905c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.app.AppOpsManager;
+import android.appwidget.AppWidgetManager;
 import com.android.internal.R;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.ProcessStats;
@@ -29,6 +30,7 @@
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.firewall.IntentFirewall;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.WindowManagerService;
@@ -273,6 +275,8 @@
 
     public ActivityStack mMainStack;
 
+    public IntentFirewall mIntentFirewall;
+
     private final boolean mHeadless;
 
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
@@ -569,8 +573,8 @@
         }
 
         @Override
-        protected String packageForFilter(BroadcastFilter filter) {
-            return filter.packageName;
+        protected boolean isPackageForFilter(String packageName, BroadcastFilter filter) {
+            return packageName.equals(filter.packageName);
         }
     };
 
@@ -1406,7 +1410,7 @@
     public static void setSystemProcess() {
         try {
             ActivityManagerService m = mSelf;
-            
+
             ServiceManager.addService("activity", m, true);
             ServiceManager.addService("meminfo", new MemBinder(m));
             ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
@@ -1444,6 +1448,11 @@
         mWindowManager = wm;
     }
 
+    public void startObservingNativeCrashes() {
+        final NativeCrashListener ncl = new NativeCrashListener();
+        ncl.start();
+    }
+
     public static final Context main(int factoryTest) {
         AThread thr = new AThread();
         thr.start();
@@ -1466,7 +1475,8 @@
         m.mContext = context;
         m.mFactoryTest = factoryTest;
         m.mMainStack = new ActivityStack(m, context, true, thr.mLooper);
-        
+        m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface());
+
         m.mBatteryStatsService.publish(context);
         m.mUsageStatsService.publish(context);
         m.mAppOpsService.publish(context);
@@ -2194,7 +2204,7 @@
             // the PID of the new process, or else throw a RuntimeException.
             Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                     app.processName, uid, uid, gids, debugFlags, mountExternal,
-                    app.info.targetSdkVersion, null, null);
+                    app.info.targetSdkVersion, app.info.seinfo, null);
 
             BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
             synchronized (bs) {
@@ -3499,7 +3509,14 @@
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
-                    Slog.w(TAG, "Invalid packageName:" + packageName);
+                    Slog.w(TAG, "Invalid packageName: " + packageName);
+                    if (observer != null) {
+                        try {
+                            observer.onRemoveCompleted(packageName, false);
+                        } catch (RemoteException e) {
+                            Slog.i(TAG, "Observer no longer exists.");
+                        }
+                    }
                     return false;
                 }
                 if (uid == pkgUid || checkComponentPermission(
@@ -3841,6 +3858,9 @@
                     if (app.userId != userId) {
                         continue;
                     }
+                    if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) {
+                        continue;
+                    }
                 // Package has been specified, we want to hit all processes
                 // that match it.  We need to qualify this by the processes
                 // that are running under the specified app and user ID.
@@ -4935,6 +4955,14 @@
         }
     }
 
+    class IntentFirewallInterface implements IntentFirewall.AMSInterface {
+        public int checkComponentPermission(String permission, int pid, int uid,
+                int owningUid, boolean exported) {
+            return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
+                    owningUid, exported);
+        }
+    }
+
     /**
      * This can be called with or without the global lock held.
      */
@@ -7708,6 +7736,18 @@
     }
 
     @Override
+    public void killUid(int uid, String reason) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("killUid only available to the system");
+        }
+        synchronized (this) {
+            killPackageProcessesLocked(null, UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+                    ProcessList.FOREGROUND_APP_ADJ-1, false, true, true, false,
+                    reason != null ? reason : "kill uid");
+        }
+    }
+
+    @Override
     public boolean killProcessesBelowForeground(String reason) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("killProcessesBelowForeground() only available to system");
@@ -8325,6 +8365,14 @@
         final String processName = app == null ? "system_server"
                 : (r == null ? "unknown" : r.processName);
 
+        handleApplicationCrashInner("crash", r, processName, crashInfo);
+    }
+
+    /* Native crash reporting uses this inner version because it needs to be somewhat
+     * decoupled from the AM-managed cleanup lifecycle
+     */
+    void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
+            ApplicationErrorReport.CrashInfo crashInfo) {
         EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                 UserHandle.getUserId(Binder.getCallingUid()), processName,
                 r == null ? -1 : r.info.flags,
@@ -8333,7 +8381,7 @@
                 crashInfo.throwFileName,
                 crashInfo.throwLineNumber);
 
-        addErrorToDropBox("crash", r, processName, null, null, null, null, null, crashInfo);
+        addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
 
         crashApplication(r, crashInfo);
     }
@@ -8838,7 +8886,7 @@
             return null;
         }
 
-        if (!r.crashing && !r.notResponding) {
+        if (!r.crashing && !r.notResponding && !r.forceCrashReport) {
             return null;
         }
 
@@ -8849,7 +8897,7 @@
         report.time = timeMillis;
         report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
 
-        if (r.crashing) {
+        if (r.crashing || r.forceCrashReport) {
             report.type = ApplicationErrorReport.TYPE_CRASH;
             report.crashInfo = crashInfo;
         } else if (r.notResponding) {
@@ -10859,7 +10907,7 @@
         mProcessesToGc.remove(app);
         
         // Dismiss any open dialogs.
-        if (app.crashDialog != null) {
+        if (app.crashDialog != null && !app.forceCrashReport) {
             app.crashDialog.dismiss();
             app.crashDialog = null;
         }
@@ -11784,6 +11832,32 @@
                             + callingPid + ", uid=" + callingUid;
                     Slog.w(TAG, msg);
                     throw new SecurityException(msg);
+                } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
+                    // Special case for compatibility: we don't want apps to send this,
+                    // but historically it has not been protected and apps may be using it
+                    // to poke their own app widget.  So, instead of making it protected,
+                    // just limit it to the caller.
+                    if (callerApp == null) {
+                        String msg = "Permission Denial: not allowed to send broadcast "
+                                + intent.getAction() + " from unknown caller.";
+                        Slog.w(TAG, msg);
+                        throw new SecurityException(msg);
+                    } else if (intent.getComponent() != null) {
+                        // They are good enough to send to an explicit component...  verify
+                        // it is being sent to the calling app.
+                        if (!intent.getComponent().getPackageName().equals(
+                                callerApp.info.packageName)) {
+                            String msg = "Permission Denial: not allowed to send broadcast "
+                                    + intent.getAction() + " to "
+                                    + intent.getComponent().getPackageName() + " from "
+                                    + callerApp.info.packageName;
+                            Slog.w(TAG, msg);
+                            throw new SecurityException(msg);
+                        }
+                    } else {
+                        // Limit broadcast to their own package.
+                        intent.setPackage(callerApp.info.packageName);
+                    }
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Remote exception", e);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 5902f21..0f1700d 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2490,6 +2490,7 @@
         int err = ActivityManager.START_SUCCESS;
 
         ProcessRecord callerApp = null;
+
         if (caller != null) {
             callerApp = mService.getRecordForAppLocked(caller);
             if (callerApp != null) {
@@ -2593,34 +2594,36 @@
             throw new SecurityException(msg);
         }
 
+        boolean abort = !mService.mIntentFirewall.checkStartActivity(intent,
+                callerApp==null?null:callerApp.info, callingUid, callingPid, resolvedType, aInfo);
+
         if (mMainStack) {
             if (mService.mController != null) {
-                boolean abort = false;
                 try {
                     // The Intent we give to the watcher has the extra data
                     // stripped off, since it can contain private information.
                     Intent watchIntent = intent.cloneFilter();
-                    abort = !mService.mController.activityStarting(watchIntent,
+                    abort |= !mService.mController.activityStarting(watchIntent,
                             aInfo.applicationInfo.packageName);
                 } catch (RemoteException e) {
                     mService.mController = null;
                 }
-    
-                if (abort) {
-                    if (resultRecord != null) {
-                        sendActivityResultLocked(-1,
-                            resultRecord, resultWho, requestCode,
-                            Activity.RESULT_CANCELED, null);
-                    }
-                    // We pretend to the caller that it was really started, but
-                    // they will just get a cancel result.
-                    mDismissKeyguardOnNextActivity = false;
-                    ActivityOptions.abort(options);
-                    return ActivityManager.START_SUCCESS;
-                }
             }
         }
 
+        if (abort) {
+            if (resultRecord != null) {
+                sendActivityResultLocked(-1,
+                    resultRecord, resultWho, requestCode,
+                    Activity.RESULT_CANCELED, null);
+            }
+            // We pretend to the caller that it was really started, but
+            // they will just get a cancel result.
+            mDismissKeyguardOnNextActivity = false;
+            ActivityOptions.abort(options);
+            return ActivityManager.START_SUCCESS;
+        }
+
         ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid, callingPackage,
                 intent, resolvedType, aInfo, mService.mConfiguration,
                 resultRecord, resultWho, requestCode, componentSpecified);
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index e8e8f25..ac7eb89 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -29,7 +29,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1080,6 +1079,9 @@
                 pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
                 pw.print("    ");
                 pw.println(r.intent.toShortString(false, true, true, false));
+                if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
+                    pw.print("    targetComp: "); pw.println(r.targetComp.toShortString());
+                }
                 Bundle bundle = r.intent.getExtras();
                 if (bundle != null) {
                     pw.print("    extras: "); pw.println(bundle.toString());
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index a98afb6..83cc0ea 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -38,6 +38,7 @@
  */
 class BroadcastRecord extends Binder {
     final Intent intent;    // the original intent that generated us
+    final ComponentName targetComp; // original component name set on the intent
     final ProcessRecord callerApp; // process that sent this
     final String callerPackage; // who sent this
     final int callingPid;   // the pid of who sent this
@@ -84,9 +85,12 @@
 
         pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
         pw.print(prefix); pw.println(intent.toInsecureString());
+        if (targetComp != null && targetComp != intent.getComponent()) {
+            pw.print(prefix); pw.print("  targetComp: "); pw.println(targetComp.toShortString());
+        }
         Bundle bundle = intent.getExtras();
         if (bundle != null) {
-            pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
+            pw.print(prefix); pw.print("  extras: "); pw.println(bundle.toString());
         }
         pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" ");
                 pw.print(callerApp != null ? callerApp.toShortString() : "null");
@@ -174,6 +178,7 @@
             int _userId) {
         queue = _queue;
         intent = _intent;
+        targetComp = _intent.getComponent();
         callerApp = _callerApp;
         callerPackage = _callerPackage;
         callingPid = _callingPid;
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java
new file mode 100644
index 0000000..0688c50
--- /dev/null
+++ b/services/java/com/android/server/am/NativeCrashListener.java
@@ -0,0 +1,264 @@
+/*
+ * 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.server.am;
+
+import android.app.ApplicationErrorReport.CrashInfo;
+import android.util.Slog;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructTimeval;
+import libcore.io.StructUcred;
+
+import static libcore.io.OsConstants.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.net.InetSocketAddress;
+import java.net.InetUnixAddress;
+
+/**
+ * Set up a Unix domain socket that debuggerd will connect() to in
+ * order to write a description of a native crash.  The crash info is
+ * then parsed and forwarded to the ActivityManagerService's normal
+ * crash handling code.
+ *
+ * Note that this component runs in a separate thread.
+ */
+class NativeCrashListener extends Thread {
+    static final String TAG = "NativeCrashListener";
+    static final boolean 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
+
+    final ActivityManagerService mAm;
+
+    /*
+     * Spin the actual work of handling a debuggerd crash report into a
+     * separate thread so that the listener can go immediately back to
+     * accepting incoming connections.
+     */
+    class NativeCrashReporter extends Thread {
+        ProcessRecord mApp;
+        int mSignal;
+        String mCrashReport;
+
+        NativeCrashReporter(ProcessRecord app, int signal, String report) {
+            super("NativeCrashReport");
+            mApp = app;
+            mSignal = signal;
+            mCrashReport = report;
+        }
+
+        @Override
+        public void run() {
+            try {
+                CrashInfo ci = new CrashInfo();
+                ci.exceptionClassName = "Native crash";
+                ci.exceptionMessage = Libcore.os.strsignal(mSignal);
+                ci.throwFileName = "unknown";
+                ci.throwClassName = "unknown";
+                ci.throwMethodName = "unknown";
+                ci.stackTrace = mCrashReport;
+
+                if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()");
+                mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
+                if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned");
+            } catch (Exception e) {
+                Slog.e(TAG, "Unable to report native crash", e);
+            }
+        }
+    }
+
+    /*
+     * Daemon thread that accept()s incoming domain socket connections from debuggerd
+     * and processes the crash dump that is passed through.
+     */
+    NativeCrashListener() {
+        mAm = ActivityManagerService.self();
+    }
+
+    @Override
+    public void run() {
+        final byte[] ackSignal = new byte[1];
+
+        if (DEBUG) Slog.i(TAG, "Starting up");
+
+        // The file system entity for this socket is created with 0700 perms, owned
+        // by system:system.  debuggerd runs as root, so is capable of connecting to
+        // it, but 3rd party apps cannot.
+        {
+            File socketFile = new File(DEBUGGERD_SOCKET_PATH);
+            if (socketFile.exists()) {
+                socketFile.delete();
+            }
+        }
+
+        try {
+            FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
+            final InetUnixAddress sockAddr = new InetUnixAddress(DEBUGGERD_SOCKET_PATH);
+            Libcore.os.bind(serverFd, sockAddr, 0);
+            Libcore.os.listen(serverFd, 1);
+
+            while (true) {
+                InetSocketAddress peer = new InetSocketAddress();
+                FileDescriptor peerFd = null;
+                try {
+                    if (DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
+                    peerFd = Libcore.os.accept(serverFd, peer);
+                    if (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 =
+                                Libcore.os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
+                        if (credentials.uid == 0) {
+                            // the reporting thread may take responsibility for
+                            // acking the debugger; make sure we play along.
+                            consumeNativeCrashData(peerFd);
+                        }
+                    }
+                } catch (Exception e) {
+                    Slog.w(TAG, "Error handling connection", e);
+                } finally {
+                    // Always ack debuggerd's connection to us.  The actual
+                    // byte written is irrelevant.
+                    if (peerFd != null) {
+                        try {
+                            Libcore.os.write(peerFd, ackSignal, 0, 1);
+                        } catch (Exception e) { /* we don't care about failures here */ }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to init native debug socket!", e);
+        }
+    }
+
+    static int unpackInt(byte[] buf, int offset) {
+        int b0, b1, b2, b3;
+
+        b0 = ((int) buf[offset]) & 0xFF; // mask against sign extension
+        b1 = ((int) buf[offset+1]) & 0xFF;
+        b2 = ((int) buf[offset+2]) & 0xFF;
+        b3 = ((int) buf[offset+3]) & 0xFF;
+        return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
+    }
+
+    static int readExactly(FileDescriptor fd, byte[] buffer, int offset, int numBytes)
+            throws ErrnoException {
+        int totalRead = 0;
+        while (numBytes > 0) {
+            int n = Libcore.os.read(fd, buffer, offset + totalRead, numBytes);
+            if (n <= 0) {
+                if (DEBUG) {
+                    Slog.w(TAG, "Needed " + numBytes + " but saw " + n);
+                }
+                return -1;  // premature EOF or timeout
+            }
+            numBytes -= n;
+            totalRead += n;
+        }
+        return totalRead;
+    }
+
+    // Read the crash report from the debuggerd connection
+    void consumeNativeCrashData(FileDescriptor fd) {
+        if (DEBUG) Slog.i(TAG, "debuggerd connected");
+        final byte[] buf = new byte[4096];
+        final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);
+
+        try {
+            StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);
+            Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
+            Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
+
+            // first, the pid and signal number
+            int headerBytes = readExactly(fd, buf, 0, 8);
+            if (headerBytes != 8) {
+                // protocol failure; give up
+                Slog.e(TAG, "Unable to read from debuggerd");
+                return;
+            }
+
+            int pid = unpackInt(buf, 0);
+            int signal = unpackInt(buf, 4);
+            if (DEBUG) {
+                Slog.v(TAG, "Read pid=" + pid + " signal=" + signal);
+            }
+
+            // now the text of the dump
+            if (pid > 0) {
+                final ProcessRecord pr;
+                synchronized (mAm.mPidsSelfLocked) {
+                    pr = mAm.mPidsSelfLocked.get(pid);
+                }
+                if (pr != null) {
+                    int bytes;
+                    do {
+                        // get some data
+                        bytes = Libcore.os.read(fd, buf, 0, buf.length);
+                        if (bytes > 0) {
+                            if (DEBUG) {
+                                String s = new String(buf, 0, bytes, "UTF-8");
+                                Slog.v(TAG, "READ=" + bytes + "> " + s);
+                            }
+                            // did we just get the EOD null byte?
+                            if (buf[bytes-1] == 0) {
+                                os.write(buf, 0, bytes-1);  // exclude the EOD token
+                                break;
+                            }
+                            // no EOD, so collect it and read more
+                            os.write(buf, 0, bytes);
+                        }
+                    } while (bytes > 0);
+
+                    // Okay, we've got the report.
+                    if (DEBUG) Slog.v(TAG, "processing");
+
+                    // Mark the process record as being a native crash so that the
+                    // cleanup mechanism knows we're still submitting the report
+                    // even though the process will vanish as soon as we let
+                    // debuggerd proceed.
+                    synchronized (mAm) {
+                        pr.crashing = true;
+                        pr.forceCrashReport = true;
+                    }
+
+                    // Crash reporting is synchronous but we want to let debuggerd
+                    // go about it business right away, so we spin off the actual
+                    // reporting logic on a thread and let it take it's time.
+                    final String reportString = new String(os.toByteArray(), "UTF-8");
+                    (new NativeCrashReporter(pr, signal, reportString)).start();
+                } else {
+                    Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid);
+                }
+            } else {
+                Slog.e(TAG, "Bogus pid!");
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception dealing with report", e);
+            // ugh, fail.
+        }
+    }
+
+}
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index 9e25e30..1a635a9 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -144,8 +144,8 @@
     // These are the high-end OOM level limits.  This is appropriate for a
     // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
     private final long[] mOomMinFreeHigh = new long[] {
-            32768, 40960, 49152,
-            57344, 65536, 81920
+            49152, 61440, 73728,
+            86016, 98304, 122880
     };
     // The actual OOM killer memory levels we are using.
     private final long[] mOomMinFree = new long[mOomAdj.length];
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index a32af2f..7929f96 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -138,6 +138,7 @@
     boolean persistent;         // always keep this application running?
     boolean crashing;           // are we in the process of crashing?
     Dialog crashDialog;         // dialog being displayed due to crash.
+    boolean forceCrashReport;   // suppress normal auto-dismiss of crash dialog & report UI?
     boolean notResponding;      // does the app have a not responding dialog?
     Dialog anrDialog;           // dialog being displayed due to app not resp.
     boolean removed;            // has app package been removed from device?
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index b06c60a..fccaab5 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.provider.Settings;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.NotificationManagerService;
 
@@ -368,6 +371,51 @@
                         return;
                     }
                     try {
+                        if (foregroundNoti.icon == 0) {
+                            // It is not correct for the caller to supply a notification
+                            // icon, but this used to be able to slip through, so for
+                            // those dirty apps give it the app's icon.
+                            foregroundNoti.icon = appInfo.icon;
+
+                            // Do not allow apps to present a sneaky invisible content view either.
+                            foregroundNoti.contentView = null;
+                            foregroundNoti.bigContentView = null;
+                            CharSequence appName = appInfo.loadLabel(
+                                    ams.mContext.getPackageManager());
+                            if (appName == null) {
+                                appName = appInfo.packageName;
+                            }
+                            Context ctx = null;
+                            try {
+                                ctx = ams.mContext.createPackageContext(
+                                        appInfo.packageName, 0);
+                                Intent runningIntent = new Intent(
+                                        Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                                runningIntent.setData(Uri.fromParts("package",
+                                        appInfo.packageName, null));
+                                PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
+                                        runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                                foregroundNoti.setLatestEventInfo(ctx,
+                                        ams.mContext.getString(
+                                                com.android.internal.R.string
+                                                        .app_running_notification_title,
+                                                appName),
+                                        ams.mContext.getString(
+                                                com.android.internal.R.string
+                                                        .app_running_notification_text,
+                                                appName),
+                                        pi);
+                            } catch (PackageManager.NameNotFoundException e) {
+                                foregroundNoti.icon = 0;
+                            }
+                        }
+                        if (foregroundNoti.icon == 0) {
+                            // Notifications whose icon is 0 are defined to not show
+                            // a notification, silently ignoring it.  We don't want to
+                            // just ignore it, we want to prevent the service from
+                            // being foreground.
+                            throw new RuntimeException("icon must be non-zero");
+                        }
                         int[] outId = new int[1];
                         nm.enqueueNotificationInternal(localPackageName, localPackageName,
                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java
new file mode 100644
index 0000000..59403c5
--- /dev/null
+++ b/services/java/com/android/server/connectivity/Nat464Xlat.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+
+import java.net.Inet4Address;
+
+import android.content.Context;
+import android.net.IConnectivityManager;
+import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkStateTracker;
+import android.net.NetworkUtils;
+import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.net.BaseNetworkObserver;
+
+/**
+ * @hide
+ *
+ * Class to manage a 464xlat CLAT daemon.
+ */
+public class Nat464Xlat extends BaseNetworkObserver {
+    private Context mContext;
+    private INetworkManagementService mNMService;
+    private IConnectivityManager mConnService;
+    private NetworkStateTracker mTracker;
+    private Handler mHandler;
+
+    // Whether we started clatd and expect it to be running.
+    private boolean mIsStarted;
+    // Whether the clatd interface exists (i.e., clatd is running).
+    private boolean mIsRunning;
+    // The LinkProperties of the clat interface.
+    private LinkProperties mLP;
+
+    // This must match the interface name in clatd.conf.
+    private static final String CLAT_INTERFACE_NAME = "clat4";
+
+    private static final String TAG = "Nat464Xlat";
+
+    public Nat464Xlat(Context context, INetworkManagementService nmService,
+                      IConnectivityManager connService, Handler handler) {
+        mContext = context;
+        mNMService = nmService;
+        mConnService = connService;
+        mHandler = handler;
+
+        mIsStarted = false;
+        mIsRunning = false;
+        mLP = new LinkProperties();
+    }
+
+    /**
+     * Determines whether an interface requires clat.
+     * @param netType the network type (one of the
+     *   android.net.ConnectivityManager.TYPE_* constants)
+     * @param tracker the NetworkStateTracker corresponding to the network type.
+     * @return true if the interface requires clat, false otherwise.
+     */
+    public boolean requiresClat(int netType, NetworkStateTracker tracker) {
+        LinkProperties lp = tracker.getLinkProperties();
+        // Only support clat on mobile for now.
+        Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" +
+               lp.hasIPv4Address());
+        return netType == TYPE_MOBILE && !lp.hasIPv4Address();
+    }
+
+    public static boolean isRunningClat(LinkProperties lp) {
+      return lp != null && lp.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME);
+    }
+
+    /**
+     * Starts the clat daemon.
+     * @param lp The link properties of the interface to start clatd on.
+     */
+    public void startClat(NetworkStateTracker tracker) {
+        if (mIsStarted) {
+            Slog.e(TAG, "startClat: already started");
+            return;
+        }
+        mTracker = tracker;
+        LinkProperties lp = mTracker.getLinkProperties();
+        String iface = lp.getInterfaceName();
+        Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp);
+        try {
+            mNMService.startClatd(iface);
+        } catch(RemoteException e) {
+            Slog.e(TAG, "Error starting clat daemon: " + e);
+        }
+        mIsStarted = true;
+    }
+
+    /**
+     * Stops the clat daemon.
+     */
+    public void stopClat() {
+        if (mIsStarted) {
+            Slog.i(TAG, "Stopping clatd");
+            try {
+                mNMService.stopClatd();
+            } catch(RemoteException e) {
+                Slog.e(TAG, "Error stopping clat daemon: " + e);
+            }
+            mIsStarted = false;
+            mIsRunning = false;
+            mTracker = null;
+            mLP.clear();
+        } else {
+            Slog.e(TAG, "stopClat: already stopped");
+        }
+    }
+
+    public boolean isStarted() {
+        return mIsStarted;
+    }
+
+    public boolean isRunning() {
+        return mIsRunning;
+    }
+
+    @Override
+    public void interfaceAdded(String iface) {
+        if (iface.equals(CLAT_INTERFACE_NAME)) {
+            Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
+                   " added, mIsRunning = " + mIsRunning + " -> true");
+            mIsRunning = true;
+
+            // Get the network configuration of the clat interface, store it
+            // in our link properties, and stack it on top of the interface
+            // it's running on.
+            try {
+                InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
+                mLP.clear();
+                mLP.setInterfaceName(iface);
+                RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), null,
+                                                      iface);
+                mLP.addRoute(ipv4Default);
+                mLP.addLinkAddress(config.getLinkAddress());
+                mTracker.addStackedLink(mLP);
+                Slog.i(TAG, "Adding stacked link. tracker LP: " +
+                       mTracker.getLinkProperties());
+            } catch(RemoteException e) {
+                Slog.e(TAG, "Error getting link properties: " + e);
+            }
+
+            // Inform ConnectivityService that things have changed.
+            Message msg = mHandler.obtainMessage(
+                NetworkStateTracker.EVENT_CONFIGURATION_CHANGED,
+                mTracker.getNetworkInfo());
+            Slog.i(TAG, "sending message to ConnectivityService: " + msg);
+            msg.sendToTarget();
+        }
+    }
+
+    @Override
+    public void interfaceRemoved(String iface) {
+        if (iface == CLAT_INTERFACE_NAME) {
+            if (mIsRunning) {
+                NetworkUtils.resetConnections(
+                    CLAT_INTERFACE_NAME,
+                    NetworkUtils.RESET_IPV4_ADDRESSES);
+            }
+            Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
+                   " removed, mIsRunning = " + mIsRunning + " -> false");
+            mIsRunning = false;
+            mTracker.removeStackedLink(mLP);
+            mLP.clear();
+            Slog.i(TAG, "mLP = " + mLP);
+        }
+    }
+};
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index e4a7ead..32f39b7 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -35,6 +35,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.NetworkUtils;
+import android.net.RouteInfo;
 import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -1345,7 +1346,21 @@
                         linkProperties = mConnService.getLinkProperties(upType);
                     } catch (RemoteException e) { }
                     if (linkProperties != null) {
-                        iface = linkProperties.getInterfaceName();
+                        // Find the interface with the default IPv4 route. It may be the
+                        // interface described by linkProperties, or one of the interfaces
+                        // stacked on top of it.
+                        Log.i(TAG, "Finding IPv4 upstream interface on: " + linkProperties);
+                        RouteInfo ipv4Default = RouteInfo.selectBestRoute(
+                            linkProperties.getAllRoutes(), Inet4Address.ANY);
+                        if (ipv4Default != null) {
+                            iface = ipv4Default.getInterface();
+                            Log.i(TAG, "Found interface " + ipv4Default.getInterface());
+                        } else {
+                            Log.i(TAG, "No IPv4 upstream interface, giving up.");
+                        }
+                    }
+
+                    if (iface != null) {
                         String[] dnsServers = mDefaultDnsServers;
                         Collection<InetAddress> dnses = linkProperties.getDnses();
                         if (dnses != null) {
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 3b92338..68cf5fc 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -38,6 +38,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseIntArray;
 
 import java.io.FileDescriptor;
@@ -406,6 +407,12 @@
                 "no permission to write the sync settings");
         int userId = UserHandle.getCallingUserId();
 
+        if (pollFrequency < 60) {
+            Slog.w(TAG, "Requested poll frequency of " + pollFrequency
+                    + " seconds being rounded up to 60 seconds.");
+            pollFrequency = 60;
+        }
+
         long identityToken = clearCallingIdentity();
         try {
             getSyncManager().getSyncStorageEngine().addPeriodicSync(
diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/java/com/android/server/firewall/AndFilter.java
new file mode 100644
index 0000000..e4276d0
--- /dev/null
+++ b/services/java/com/android/server/firewall/AndFilter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+class AndFilter extends FilterList {
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        for (int i=0; i<children.size(); i++) {
+            if (!children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+                    resolvedApp)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("and") {
+        @Override
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            return new AndFilter().readFromXml(parser);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/java/com/android/server/firewall/CategoryFilter.java
new file mode 100644
index 0000000..4938cb8
--- /dev/null
+++ b/services/java/com/android/server/firewall/CategoryFilter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.Set;
+
+class CategoryFilter implements Filter {
+    private static final String ATTR_NAME = "name";
+
+    private final String mCategoryName;
+
+    private CategoryFilter(String categoryName) {
+        mCategoryName = categoryName;
+    }
+
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        Set<String> categories = intent.getCategories();
+        if (categories == null) {
+            return false;
+        }
+        return categories.contains(mCategoryName);
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("category") {
+        @Override
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            String categoryName = parser.getAttributeValue(null, ATTR_NAME);
+            if (categoryName == null) {
+                throw new XmlPullParserException("Category name must be specified.",
+                        parser, null);
+            }
+            return new CategoryFilter(categoryName);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/Filter.java b/services/java/com/android/server/firewall/Filter.java
new file mode 100644
index 0000000..0e783e8
--- /dev/null
+++ b/services/java/com/android/server/firewall/Filter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+
+interface Filter {
+    /**
+     * Does the given intent + context info match this filter?
+     *
+     * @param ifw The IntentFirewall instance
+     * @param intent The intent being started/bound/broadcast
+     * @param callerApp An ApplicationInfo of an application in the caller's process. This may not
+     *                  be the specific app that is actually sending the intent. This also may be
+     *                  null, if the caller is the system process, or an unrecognized process (e.g.
+     *                  am start)
+     * @param callerUid
+     * @param callerPid
+     * @param resolvedType The resolved mime type of the intent
+     * @param resolvedApp The application that contains the resolved component that the intent is
+     */
+    boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp);
+}
diff --git a/services/java/com/android/server/firewall/FilterFactory.java b/services/java/com/android/server/firewall/FilterFactory.java
new file mode 100644
index 0000000..dea8b40
--- /dev/null
+++ b/services/java/com/android/server/firewall/FilterFactory.java
@@ -0,0 +1,40 @@
+/*
+ * 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.server.firewall;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public abstract class FilterFactory {
+    private final String mTag;
+
+    protected FilterFactory(String tag) {
+        if (tag == null) {
+            throw new NullPointerException();
+        }
+        mTag = tag;
+    }
+
+    public String getTagName() {
+        return mTag;
+    }
+
+    public abstract Filter newFilter(XmlPullParser parser)
+            throws IOException, XmlPullParserException;
+}
diff --git a/services/java/com/android/server/firewall/FilterList.java b/services/java/com/android/server/firewall/FilterList.java
new file mode 100644
index 0000000..d34b203
--- /dev/null
+++ b/services/java/com/android/server/firewall/FilterList.java
@@ -0,0 +1,41 @@
+/*
+ * 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.server.firewall;
+
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+abstract class FilterList implements Filter {
+    protected final ArrayList<Filter> children = new ArrayList<Filter>();
+
+    public FilterList readFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+        int outerDepth = parser.getDepth();
+        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+            readChild(parser);
+        }
+        return this;
+    }
+
+    protected void readChild(XmlPullParser parser) throws IOException, XmlPullParserException {
+        Filter filter = IntentFirewall.parseFilter(parser);
+        children.add(filter);
+    }
+}
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
new file mode 100644
index 0000000..08e6b45
--- /dev/null
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -0,0 +1,401 @@
+/*
+ * 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.server.firewall;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import com.android.server.EventLogTags;
+import com.android.server.IntentResolver;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class IntentFirewall {
+    private static final String TAG = "IntentFirewall";
+
+    // e.g. /data/system/ifw/ifw.xml or /data/secure/system/ifw/ifw.xml
+    private static final File RULES_FILE =
+            new File(Environment.getSystemSecureDirectory(), "ifw/ifw.xml");
+
+    private static final int LOG_PACKAGES_MAX_LENGTH = 150;
+    private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
+
+    private static final String TAG_RULES = "rules";
+    private static final String TAG_ACTIVITY = "activity";
+    private static final String TAG_SERVICE = "service";
+    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 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();
+
+    static {
+        FilterFactory[] factories = new FilterFactory[] {
+                AndFilter.FACTORY,
+                OrFilter.FACTORY,
+                NotFilter.FACTORY,
+
+                StringFilter.ACTION,
+                StringFilter.COMPONENT,
+                StringFilter.COMPONENT_NAME,
+                StringFilter.COMPONENT_PACKAGE,
+                StringFilter.DATA,
+                StringFilter.HOST,
+                StringFilter.MIME_TYPE,
+                StringFilter.PATH,
+                StringFilter.SSP,
+
+                CategoryFilter.FACTORY,
+                SenderFilter.FACTORY,
+                SenderPermissionFilter.FACTORY,
+                PortFilter.FACTORY
+        };
+
+        // load factor ~= .75
+        factoryMap = new HashMap<String, FilterFactory>(factories.length * 4 / 3);
+        for (int i=0; i<factories.length; i++) {
+            FilterFactory factory = factories[i];
+            factoryMap.put(factory.getTagName(), factory);
+        }
+    }
+
+    public IntentFirewall(AMSInterface ams) {
+        mAms = ams;
+        readRules(getRulesFile());
+    }
+
+    public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp, int callerUid,
+            int callerPid, String resolvedType, ActivityInfo resolvedActivity) {
+        List<Rule> matchingRules = mActivityResolver.queryIntent(intent, resolvedType, false, 0);
+        boolean log = false;
+        boolean block = false;
+
+        for (int i=0; i< matchingRules.size(); i++) {
+            Rule rule = matchingRules.get(i);
+            if (rule.matches(this, intent, callerApp, callerUid, callerPid, resolvedType,
+                    resolvedActivity.applicationInfo)) {
+                block |= rule.getBlock();
+                log |= rule.getLog();
+
+                // if we've already determined that we should both block and log, there's no need
+                // to continue trying rules
+                if (block && log) {
+                    break;
+                }
+            }
+        }
+
+        if (log) {
+            logIntent(TYPE_ACTIVITY, intent, callerUid, resolvedType);
+        }
+
+        return !block;
+    }
+
+    private static void logIntent(int intentType, Intent intent, int callerUid,
+            String resolvedType) {
+        // The component shouldn't be null, but let's double check just to be safe
+        ComponentName cn = intent.getComponent();
+        String shortComponent = null;
+        if (cn != null) {
+            shortComponent = cn.flattenToShortString();
+        }
+
+        String callerPackages = null;
+        int callerPackageCount = 0;
+        IPackageManager pm = AppGlobals.getPackageManager();
+        if (pm != null) {
+            try {
+                String[] callerPackagesArray = pm.getPackagesForUid(callerUid);
+                if (callerPackagesArray != null) {
+                    callerPackageCount = callerPackagesArray.length;
+                    callerPackages = joinPackages(callerPackagesArray);
+                }
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Remote exception while retrieving packages", ex);
+            }
+        }
+
+        EventLogTags.writeIfwIntentMatched(intentType, shortComponent, callerUid,
+                callerPackageCount, callerPackages, intent.getAction(), resolvedType,
+                intent.getDataString(), intent.getFlags());
+    }
+
+    /**
+     * Joins a list of package names such that the resulting string is no more than
+     * LOG_PACKAGES_MAX_LENGTH.
+     *
+     * Only full package names will be added to the result, unless every package is longer than the
+     * limit, in which case one of the packages will be truncated and added. In this case, an
+     * additional '-' character will be added to the end of the string, to denote the truncation.
+     *
+     * If it encounters a package that won't fit in the remaining space, it will continue on to the
+     * next package, unless the total length of the built string so far is greater than
+     * LOG_PACKAGES_SUFFICIENT_LENGTH, in which case it will stop and return what it has.
+     */
+    private static String joinPackages(String[] packages) {
+        boolean first = true;
+        StringBuilder sb = new StringBuilder();
+        for (int i=0; i<packages.length; i++) {
+            String pkg = packages[i];
+
+            // + 1 length for the comma. This logic technically isn't correct for the first entry,
+            // but it's not critical.
+            if (sb.length() + pkg.length() + 1 < LOG_PACKAGES_MAX_LENGTH) {
+                if (!first) {
+                    sb.append(',');
+                } else {
+                    first = false;
+                }
+                sb.append(pkg);
+            } else if (sb.length() >= LOG_PACKAGES_SUFFICIENT_LENGTH) {
+                return sb.toString();
+            }
+        }
+        if (sb.length() == 0 && packages.length > 0) {
+            String pkg = packages[0];
+            // truncating from the end - the last part of the package name is more likely to be
+            // interesting/unique
+            return pkg.substring(pkg.length() - LOG_PACKAGES_MAX_LENGTH + 1) + '-';
+        }
+        return null;
+    }
+
+    public static File getRulesFile() {
+        return RULES_FILE;
+    }
+
+    private void readRules(File rulesFile) {
+        FileInputStream fis;
+        try {
+            fis = new FileInputStream(rulesFile);
+        } catch (FileNotFoundException ex) {
+            // Nope, no rules. Nothing else to do!
+            return;
+        }
+
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+
+            parser.setInput(fis, null);
+
+            XmlUtils.beginDocument(parser, TAG_RULES);
+
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                IntentResolver<FirewallIntentFilter, Rule> resolver = null;
+                String tagName = parser.getName();
+                if (tagName.equals(TAG_ACTIVITY)) {
+                    resolver = mActivityResolver;
+                } else if (tagName.equals(TAG_SERVICE)) {
+                    resolver = mServiceResolver;
+                } else if (tagName.equals(TAG_BROADCAST)) {
+                    resolver = mBroadcastResolver;
+                }
+
+                if (resolver != null) {
+                    Rule rule = new 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;
+                    }
+
+                    for (int i=0; i<rule.getIntentFilterCount(); i++) {
+                        resolver.addFilter(rule.getIntentFilter(i));
+                    }
+                }
+            }
+        } catch (XmlPullParserException ex) {
+            Slog.e(TAG, "Error reading intent firewall rules", ex);
+        } catch (IOException ex) {
+            Slog.e(TAG, "Error reading intent firewall rules", ex);
+        } finally {
+            try {
+                fis.close();
+            } catch (IOException ex) {
+                Slog.e(TAG, "Error while closing " + rulesFile, ex);
+            }
+        }
+    }
+
+    static Filter parseFilter(XmlPullParser parser) throws IOException, XmlPullParserException {
+        String elementName = parser.getName();
+
+        FilterFactory factory = factoryMap.get(elementName);
+
+        if (factory == null) {
+            throw new XmlPullParserException("Unknown element in filter list: " + elementName);
+        }
+        return factory.newFilter(parser);
+    }
+
+    private static class Rule extends AndFilter {
+        private static final String TAG_INTENT_FILTER = "intent-filter";
+
+        private static final String ATTR_BLOCK = "block";
+        private static final String ATTR_LOG = "log";
+
+        private final ArrayList<FirewallIntentFilter> mIntentFilters =
+                new ArrayList<FirewallIntentFilter>(1);
+        private boolean block;
+        private boolean log;
+
+        @Override
+        public Rule readFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+            block = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_BLOCK));
+            log = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_LOG));
+
+            super.readFromXml(parser);
+            return this;
+        }
+
+        @Override
+        protected void readChild(XmlPullParser parser) throws IOException, XmlPullParserException {
+            if (parser.getName().equals(TAG_INTENT_FILTER)) {
+                FirewallIntentFilter intentFilter = new FirewallIntentFilter(this);
+                intentFilter.readFromXml(parser);
+                mIntentFilters.add(intentFilter);
+            } else {
+                super.readChild(parser);
+            }
+        }
+
+        public int getIntentFilterCount() {
+            return mIntentFilters.size();
+        }
+
+        public FirewallIntentFilter getIntentFilter(int index) {
+            return mIntentFilters.get(index);
+        }
+
+        public boolean getBlock() {
+            return block;
+        }
+
+        public boolean getLog() {
+            return log;
+        }
+    }
+
+    private static class FirewallIntentFilter extends IntentFilter {
+        private final Rule rule;
+
+        public FirewallIntentFilter(Rule rule) {
+            this.rule = rule;
+        }
+    }
+
+    private static class FirewallIntentResolver
+            extends IntentResolver<FirewallIntentFilter, Rule> {
+        @Override
+        protected boolean allowFilterResult(FirewallIntentFilter filter, List<Rule> dest) {
+            return !dest.contains(filter.rule);
+        }
+
+        @Override
+        protected boolean isPackageForFilter(String packageName, FirewallIntentFilter filter) {
+            return true;
+        }
+
+        @Override
+        protected FirewallIntentFilter[] newArray(int size) {
+            return new FirewallIntentFilter[size];
+        }
+
+        @Override
+        protected Rule newResult(FirewallIntentFilter filter, int match, int userId) {
+            return filter.rule;
+        }
+
+        @Override
+        protected void sortResults(List<Rule> results) {
+            // there's no need to sort the results
+            return;
+        }
+    }
+
+    /**
+     * 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
+     * component.
+     */
+    public interface AMSInterface {
+        int checkComponentPermission(String permission, int pid, int uid,
+                int owningUid, boolean exported);
+    }
+
+    /**
+     * Checks if the caller has access to a component
+     *
+     * @param permission If present, the caller must have this permission
+     * @param pid The pid of the caller
+     * @param uid The uid of the caller
+     * @param owningUid The uid of the application that owns the component
+     * @param exported Whether the component is exported
+     * @return True if the caller can access the described component
+     */
+    boolean checkComponentPermission(String permission, int pid, int uid, int owningUid,
+            boolean exported) {
+        return mAms.checkComponentPermission(permission, pid, uid, owningUid, exported) ==
+                PackageManager.PERMISSION_GRANTED;
+    }
+
+    boolean signaturesMatch(int uid1, int uid2) {
+        try {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            return pm.checkUidSignatures(uid1, uid2) == PackageManager.SIGNATURE_MATCH;
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Remote exception while checking signatures", ex);
+            return false;
+        }
+    }
+}
diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/java/com/android/server/firewall/NotFilter.java
new file mode 100644
index 0000000..f0fc337
--- /dev/null
+++ b/services/java/com/android/server/firewall/NotFilter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+class NotFilter implements Filter {
+    private final Filter mChild;
+
+    private NotFilter(Filter child) {
+        mChild = child;
+    }
+
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        return !mChild.matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+                resolvedApp);
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("not") {
+        @Override
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            Filter child = null;
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                Filter filter = IntentFirewall.parseFilter(parser);
+                if (child == null) {
+                    child = filter;
+                } else {
+                    throw new XmlPullParserException(
+                            "<not> tag can only contain a single child filter.", parser, null);
+                }
+            }
+            return new NotFilter(child);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/java/com/android/server/firewall/OrFilter.java
new file mode 100644
index 0000000..72db31e
--- /dev/null
+++ b/services/java/com/android/server/firewall/OrFilter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+class OrFilter extends FilterList {
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        for (int i=0; i<children.size(); i++) {
+            if (children.get(i).matches(ifw, intent, callerApp, callerUid, callerPid, resolvedType,
+                    resolvedApp)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("or") {
+        @Override
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            return new OrFilter().readFromXml(parser);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/java/com/android/server/firewall/PortFilter.java
new file mode 100644
index 0000000..fe7e085
--- /dev/null
+++ b/services/java/com/android/server/firewall/PortFilter.java
@@ -0,0 +1,110 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.net.Uri;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+class PortFilter implements Filter {
+    private static final String ATTR_EQUALS = "equals";
+    private static final String ATTR_MIN = "min";
+    private static final String ATTR_MAX = "max";
+
+    private static final int NO_BOUND = -1;
+
+    // both bounds are inclusive
+    private final int mLowerBound;
+    private final int mUpperBound;
+
+    private PortFilter(int lowerBound, int upperBound) {
+        mLowerBound = lowerBound;
+        mUpperBound = upperBound;
+    }
+
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        int port = -1;
+        Uri uri = intent.getData();
+        if (uri != null) {
+            port = uri.getPort();
+        }
+        return port != -1 &&
+                (mLowerBound == NO_BOUND || mLowerBound <= port) &&
+                (mUpperBound == NO_BOUND || mUpperBound >= port);
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("port") {
+        @Override
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            int lowerBound = NO_BOUND;
+            int upperBound = NO_BOUND;
+
+            String equalsValue = parser.getAttributeValue(null, ATTR_EQUALS);
+            if (equalsValue != null) {
+                int value;
+                try {
+                    value = Integer.parseInt(equalsValue);
+                } catch (NumberFormatException ex) {
+                    throw new XmlPullParserException("Invalid port value: " + equalsValue,
+                            parser, null);
+                }
+                lowerBound = value;
+                upperBound = value;
+            }
+
+            String lowerBoundString = parser.getAttributeValue(null, ATTR_MIN);
+            String upperBoundString = parser.getAttributeValue(null, ATTR_MAX);
+            if (lowerBoundString != null || upperBoundString != null) {
+                if (equalsValue != null) {
+                    throw new XmlPullParserException(
+                            "Port filter cannot use both equals and range filtering",
+                            parser, null);
+                }
+
+                if (lowerBoundString != null) {
+                    try {
+                        lowerBound = Integer.parseInt(lowerBoundString);
+                    } catch (NumberFormatException ex) {
+                        throw new XmlPullParserException(
+                                "Invalid minimum port value: " + lowerBoundString,
+                                parser, null);
+                    }
+                }
+
+                if (upperBoundString != null) {
+                    try {
+                        upperBound = Integer.parseInt(upperBoundString);
+                    } catch (NumberFormatException ex) {
+                        throw new XmlPullParserException(
+                                "Invalid maximum port value: " + upperBoundString,
+                                parser, null);
+                    }
+                }
+            }
+
+            // an empty port filter is explicitly allowed, and checks for the existence of a port
+            return new PortFilter(lowerBound, upperBound);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/java/com/android/server/firewall/SenderFilter.java
new file mode 100644
index 0000000..58bdd73
--- /dev/null
+++ b/services/java/com/android/server/firewall/SenderFilter.java
@@ -0,0 +1,111 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.os.Process;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+class SenderFilter {
+    private static final String ATTR_TYPE = "type";
+
+    private static final String VAL_SIGNATURE = "signature";
+    private static final String VAL_SYSTEM = "system";
+    private static final String VAL_SYSTEM_OR_SIGNATURE = "system|signature";
+    private static final String VAL_USER_ID = "userId";
+
+    static boolean isSystemApp(ApplicationInfo callerApp, int callerUid, int callerPid) {
+        if (callerUid == Process.SYSTEM_UID ||
+                callerPid == Process.myPid()) {
+            return true;
+        }
+        if (callerApp == null) {
+            return false;
+        }
+        return (callerApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("sender") {
+        @Override
+        public Filter newFilter(XmlPullParser parser) throws IOException, XmlPullParserException {
+            String typeString = parser.getAttributeValue(null, ATTR_TYPE);
+            if (typeString == null) {
+                throw new XmlPullParserException("type attribute must be specified for <sender>",
+                        parser, null);
+            }
+            if (typeString.equals(VAL_SYSTEM)) {
+                return SYSTEM;
+            } else if (typeString.equals(VAL_SIGNATURE)) {
+                return SIGNATURE;
+            } else if (typeString.equals(VAL_SYSTEM_OR_SIGNATURE)) {
+                return SYSTEM_OR_SIGNATURE;
+            } else if (typeString.equals(VAL_USER_ID)) {
+                return USER_ID;
+            }
+            throw new XmlPullParserException(
+                    "Invalid type attribute for <sender>: " + typeString, parser, null);
+        }
+    };
+
+    private static final Filter SIGNATURE = new Filter() {
+        @Override
+        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+            if (callerApp == null) {
+                return false;
+            }
+            return ifw.signaturesMatch(callerUid, resolvedApp.uid);
+        }
+    };
+
+    private static final Filter SYSTEM = new Filter() {
+        @Override
+        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+            if (callerApp == null) {
+                // if callerApp is null, the caller is the system process
+                return false;
+            }
+            return isSystemApp(callerApp, callerUid, callerPid);
+        }
+    };
+
+    private static final Filter SYSTEM_OR_SIGNATURE = new Filter() {
+        @Override
+        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+            return isSystemApp(callerApp, callerUid, callerPid) ||
+                    ifw.signaturesMatch(callerUid, resolvedApp.uid);
+        }
+    };
+
+    private static final Filter USER_ID = new Filter() {
+        @Override
+        public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+                int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+            // This checks whether the caller is either the system process, or has the same user id
+            // I.e. the same app, or an app that uses the same shared user id.
+            // This is the same set of applications that would be able to access the component if
+            // it wasn't exported.
+            return ifw.checkComponentPermission(null, callerPid, callerUid, resolvedApp.uid, false);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/java/com/android/server/firewall/SenderPermissionFilter.java
new file mode 100644
index 0000000..310da20
--- /dev/null
+++ b/services/java/com/android/server/firewall/SenderPermissionFilter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.server.firewall;
+
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+class SenderPermissionFilter implements Filter {
+    private static final String ATTR_NAME = "name";
+
+    private final String mPermission;
+
+    private SenderPermissionFilter(String permission) {
+        mPermission = permission;
+    }
+
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        // We assume the component is exported here. If the component is not exported, then
+        // ActivityManager would only resolve to this component for callers from the same uid.
+        // In this case, it doesn't matter whether the component is exported or not.
+        return ifw.checkComponentPermission(mPermission, callerPid, callerUid, resolvedApp.uid,
+                true);
+    }
+
+    public static final FilterFactory FACTORY = new FilterFactory("sender-permission") {
+        @Override
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            String permission = parser.getAttributeValue(null, ATTR_NAME);
+            if (permission == null) {
+                throw new XmlPullParserException("Permission name must be specified.",
+                        parser, null);
+            }
+            return new SenderPermissionFilter(permission);
+        }
+    };
+}
diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/java/com/android/server/firewall/StringFilter.java
new file mode 100644
index 0000000..ed5d3f3
--- /dev/null
+++ b/services/java/com/android/server/firewall/StringFilter.java
@@ -0,0 +1,342 @@
+/*
+ * 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.server.firewall;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.net.Uri;
+import android.os.PatternMatcher;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+abstract class StringFilter implements Filter {
+    private static final String ATTR_EQUALS = "equals";
+    private static final String ATTR_STARTS_WITH = "startsWith";
+    private static final String ATTR_CONTAINS = "contains";
+    private static final String ATTR_PATTERN = "pattern";
+    private static final String ATTR_REGEX = "regex";
+    private static final String ATTR_IS_NULL = "isNull";
+
+    private final ValueProvider mValueProvider;
+
+    private StringFilter(ValueProvider valueProvider) {
+        this.mValueProvider = valueProvider;
+    }
+
+    /**
+     * Constructs a new StringFilter based on the string filter attribute on the current
+     * element, and the given StringValueMatcher.
+     *
+     * The current node should contain exactly 1 string filter attribute. E.g. equals,
+     * contains, etc. Otherwise, an XmlPullParserException will be thrown.
+     *
+     * @param parser      An XmlPullParser object positioned at an element that should
+     *                    contain a string filter attribute
+     * @return This StringFilter object
+     */
+    public static StringFilter readFromXml(ValueProvider valueProvider, XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        StringFilter filter = null;
+
+        for (int i=0; i<parser.getAttributeCount(); i++) {
+            StringFilter newFilter = getFilter(valueProvider, parser, i);
+            if (newFilter != null) {
+                if (filter != null) {
+                    throw new XmlPullParserException("Multiple string filter attributes found");
+                }
+                filter = newFilter;
+            }
+        }
+
+        if (filter == null) {
+            // if there are no string filter attributes, we default to isNull="false" so that an
+            // empty filter is equivalent to an existence check
+            filter = new IsNullFilter(valueProvider, false);
+        }
+
+        return filter;
+    }
+
+    private static StringFilter getFilter(ValueProvider valueProvider, XmlPullParser parser,
+            int attributeIndex) {
+        String attributeName = parser.getAttributeName(attributeIndex);
+
+        switch (attributeName.charAt(0)) {
+            case 'e':
+                if (!attributeName.equals(ATTR_EQUALS)) {
+                    return null;
+                }
+                return new EqualsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
+            case 'i':
+                if (!attributeName.equals(ATTR_IS_NULL)) {
+                    return null;
+                }
+                return new IsNullFilter(valueProvider, parser.getAttributeValue(attributeIndex));
+            case 's':
+                if (!attributeName.equals(ATTR_STARTS_WITH)) {
+                    return null;
+                }
+                return new StartsWithFilter(valueProvider,
+                        parser.getAttributeValue(attributeIndex));
+            case 'c':
+                if (!attributeName.equals(ATTR_CONTAINS)) {
+                    return null;
+                }
+                return new ContainsFilter(valueProvider, parser.getAttributeValue(attributeIndex));
+            case 'p':
+                if (!attributeName.equals(ATTR_PATTERN)) {
+                    return null;
+                }
+                return new PatternStringFilter(valueProvider,
+                        parser.getAttributeValue(attributeIndex));
+            case 'r':
+                if (!attributeName.equals(ATTR_REGEX)) {
+                    return null;
+                }
+                return new RegexFilter(valueProvider, parser.getAttributeValue(attributeIndex));
+        }
+        return null;
+    }
+
+    protected abstract boolean matchesValue(String value);
+
+    @Override
+    public boolean matches(IntentFirewall ifw, Intent intent, ApplicationInfo callerApp,
+            int callerUid, int callerPid, String resolvedType, ApplicationInfo resolvedApp) {
+        String value = mValueProvider.getValue(intent, callerApp, resolvedType, resolvedApp);
+        return matchesValue(value);
+    }
+
+    private static abstract class ValueProvider extends FilterFactory {
+        protected ValueProvider(String tag) {
+            super(tag);
+        }
+
+        public Filter newFilter(XmlPullParser parser)
+                throws IOException, XmlPullParserException {
+            return StringFilter.readFromXml(this, parser);
+        }
+
+        public abstract String getValue(Intent intent, ApplicationInfo callerApp,
+                String resolvedType, ApplicationInfo resolvedApp);
+    }
+
+    private static class EqualsFilter extends StringFilter {
+        private final String mFilterValue;
+
+        public EqualsFilter(ValueProvider valueProvider, String attrValue) {
+            super(valueProvider);
+            mFilterValue = attrValue;
+        }
+
+        @Override
+        public boolean matchesValue(String value) {
+            return value != null && value.equals(mFilterValue);
+        }
+    }
+
+    private static class ContainsFilter extends StringFilter {
+        private final String mFilterValue;
+
+        public ContainsFilter(ValueProvider valueProvider, String attrValue) {
+            super(valueProvider);
+            mFilterValue = attrValue;
+        }
+
+        @Override
+        public boolean matchesValue(String value) {
+            return value != null && value.contains(mFilterValue);
+        }
+    }
+
+    private static class StartsWithFilter extends StringFilter {
+        private final String mFilterValue;
+
+        public StartsWithFilter(ValueProvider valueProvider, String attrValue) {
+            super(valueProvider);
+            mFilterValue = attrValue;
+        }
+
+        @Override
+        public boolean matchesValue(String value) {
+            return value != null && value.startsWith(mFilterValue);
+        }
+    }
+
+    private static class PatternStringFilter extends StringFilter {
+        private final PatternMatcher mPattern;
+
+        public PatternStringFilter(ValueProvider valueProvider, String attrValue) {
+            super(valueProvider);
+            mPattern = new PatternMatcher(attrValue, PatternMatcher.PATTERN_SIMPLE_GLOB);
+        }
+
+        @Override
+        public boolean matchesValue(String value) {
+            return value != null && mPattern.match(value);
+        }
+    }
+
+    private static class RegexFilter extends StringFilter {
+        private final Pattern mPattern;
+
+        public RegexFilter(ValueProvider valueProvider, String attrValue) {
+            super(valueProvider);
+            this.mPattern = Pattern.compile(attrValue);
+        }
+
+        @Override
+        public boolean matchesValue(String value) {
+            return value != null && mPattern.matcher(value).matches();
+        }
+    }
+
+    private static class IsNullFilter extends StringFilter {
+        private final boolean mIsNull;
+
+        public IsNullFilter(ValueProvider valueProvider, String attrValue) {
+            super(valueProvider);
+            mIsNull = Boolean.parseBoolean(attrValue);
+        }
+
+        public IsNullFilter(ValueProvider valueProvider, boolean isNull) {
+            super(valueProvider);
+            mIsNull = isNull;
+        }
+
+        @Override
+        public boolean matchesValue(String value) {
+            return (value == null) == mIsNull;
+        }
+    }
+
+    public static final ValueProvider COMPONENT = new ValueProvider("component") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            ComponentName cn = intent.getComponent();
+            if (cn != null) {
+                return cn.flattenToString();
+            }
+            return null;
+        }
+    };
+
+    public static final ValueProvider COMPONENT_NAME = new ValueProvider("component-name") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            ComponentName cn = intent.getComponent();
+            if (cn != null) {
+                return cn.getClassName();
+            }
+            return null;
+        }
+    };
+
+    public static final ValueProvider COMPONENT_PACKAGE = new ValueProvider("component-package") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            ComponentName cn = intent.getComponent();
+            if (cn != null) {
+                return cn.getPackageName();
+            }
+            return null;
+        }
+    };
+
+    public static final FilterFactory ACTION = new ValueProvider("action") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            return intent.getAction();
+        }
+    };
+
+    public static final ValueProvider DATA = new ValueProvider("data") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            Uri data = intent.getData();
+            if (data != null) {
+                return data.toString();
+            }
+            return null;
+        }
+    };
+
+    public static final ValueProvider MIME_TYPE = new ValueProvider("mime-type") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            return resolvedType;
+        }
+    };
+
+    public static final ValueProvider SCHEME = new ValueProvider("scheme") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            Uri data = intent.getData();
+            if (data != null) {
+                return data.getScheme();
+            }
+            return null;
+        }
+    };
+
+    public static final ValueProvider SSP = new ValueProvider("scheme-specific-part") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            Uri data = intent.getData();
+            if (data != null) {
+                return data.getSchemeSpecificPart();
+            }
+            return null;
+        }
+    };
+
+    public static final ValueProvider HOST = new ValueProvider("host") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            Uri data = intent.getData();
+            if (data != null) {
+                return data.getHost();
+            }
+            return null;
+        }
+    };
+
+    public static final ValueProvider PATH = new ValueProvider("path") {
+        @Override
+        public String getValue(Intent intent, ApplicationInfo callerApp, String resolvedType,
+                ApplicationInfo resolvedApp) {
+            Uri data = intent.getData();
+            if (data != null) {
+                return data.getPath();
+            }
+            return null;
+        }
+    };
+}
diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/java/com/android/server/location/GeofenceProxy.java
new file mode 100644
index 0000000..36e9fcc
--- /dev/null
+++ b/services/java/com/android/server/location/GeofenceProxy.java
@@ -0,0 +1,154 @@
+/*
+ * 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.server.location;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.hardware.location.GeofenceHardwareService;
+import android.hardware.location.IGeofenceHardware;
+import android.location.IGeofenceProvider;
+import android.location.IGpsGeofenceHardware;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import com.android.server.ServiceWatcher;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class GeofenceProxy {
+    private static final String TAG = "GeofenceProxy";
+    private static final String SERVICE_ACTION =
+            "com.android.location.service.GeofenceProvider";
+    private ServiceWatcher mServiceWatcher;
+    private Context mContext;
+    private IGeofenceHardware mGeofenceHardware;
+    private IGpsGeofenceHardware mGpsGeofenceHardware;
+
+    private static final int GEOFENCE_PROVIDER_CONNECTED = 1;
+    private static final int GEOFENCE_HARDWARE_CONNECTED = 2;
+    private static final int GEOFENCE_HARDWARE_DISCONNECTED = 3;
+    private static final int GEOFENCE_GPS_HARDWARE_CONNECTED = 4;
+    private static final int GEOFENCE_GPS_HARDWARE_DISCONNECTED = 5;
+
+    private Runnable mRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mHandler.sendEmptyMessage(GEOFENCE_PROVIDER_CONNECTED);
+        }
+    };
+
+    public static GeofenceProxy createAndBind(Context context,
+            List<String> initialPackageNames, Handler handler, IGpsGeofenceHardware gpsGeofence) {
+        GeofenceProxy proxy = new GeofenceProxy(context, initialPackageNames, handler, gpsGeofence);
+        if (proxy.bindGeofenceProvider()) {
+            return proxy;
+        } else {
+            return null;
+        }
+    }
+
+    private GeofenceProxy(Context context, List<String> initialPackageName, Handler handler,
+            IGpsGeofenceHardware gpsGeofence) {
+        mContext = context;
+        mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, initialPackageName,
+                mRunnable, handler);
+        mGpsGeofenceHardware = gpsGeofence;
+        bindHardwareGeofence();
+    }
+
+    private boolean bindGeofenceProvider() {
+        return mServiceWatcher.start();
+    }
+
+    private IGeofenceProvider getGeofenceProviderService() {
+        return IGeofenceProvider.Stub.asInterface(mServiceWatcher.getBinder());
+    }
+
+    private void bindHardwareGeofence() {
+        mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class),
+                mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
+    }
+
+    private ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mGeofenceHardware = IGeofenceHardware.Stub.asInterface(service);
+            mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_CONNECTED);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            mGeofenceHardware = null;
+            mHandler.sendEmptyMessage(GEOFENCE_HARDWARE_DISCONNECTED);
+        }
+    };
+
+    private void setGeofenceHardwareInProvider() {
+        try {
+            getGeofenceProviderService().setGeofenceHardware(mGeofenceHardware);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Remote Exception: setGeofenceHardwareInProvider: " + e);
+        }
+    }
+
+    private void setGpsGeofence() {
+        try {
+            mGeofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error while connecting to GeofenceHardwareService");
+        }
+    }
+
+
+    // This needs to be reworked, when more services get added,
+    // Might need a state machine or add a framework utility class,
+    private Handler mHandler = new Handler() {
+        private boolean mGeofenceHardwareConnected = false;
+        private boolean mGeofenceProviderConnected = false;
+
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case GEOFENCE_PROVIDER_CONNECTED:
+                    mGeofenceProviderConnected = true;
+                    if (mGeofenceHardwareConnected) {
+                        setGeofenceHardwareInProvider();
+                    }
+                    break;
+                case GEOFENCE_HARDWARE_CONNECTED:
+                    setGpsGeofence();
+                    mGeofenceHardwareConnected = true;
+                    if (mGeofenceProviderConnected) {
+                        setGeofenceHardwareInProvider();
+                    }
+                    break;
+                case GEOFENCE_HARDWARE_DISCONNECTED:
+                    mGeofenceHardwareConnected = false;
+                    setGeofenceHardwareInProvider();
+                    break;
+            }
+        }
+    };
+}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 3552b6a..1ebff67 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -24,7 +24,10 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.Cursor;
+import android.hardware.location.GeofenceHardwareImpl;
+import android.hardware.location.IGeofenceHardware;
 import android.location.Criteria;
+import android.location.IGpsGeofenceHardware;
 import android.location.IGpsStatusListener;
 import android.location.IGpsStatusProvider;
 import android.location.ILocationManager;
@@ -314,6 +317,8 @@
     // only modified on handler thread
     private WorkSource mClientSource = new WorkSource();
 
+    private GeofenceHardwareImpl mGeofenceHardwareImpl;
+
     private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
         @Override
         public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
@@ -367,6 +372,10 @@
         return mGpsStatusProvider;
     }
 
+    public IGpsGeofenceHardware getGpsGeofenceProxy() {
+        return mGpsGeofenceBinder;
+    }
+
     private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -918,6 +927,31 @@
         return result;
     }
 
+    private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
+        public boolean isHardwareGeofenceSupported() {
+            return native_is_geofence_supported();
+        }
+
+        public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
+                double longitude, double radius, int lastTransition, int monitorTransitions,
+                int notificationResponsiveness, int unknownTimer) {
+            return native_add_geofence(geofenceId, latitude, longitude, radius,
+                    lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
+        }
+
+        public boolean removeHardwareGeofence(int geofenceId) {
+            return native_remove_geofence(geofenceId);
+        }
+
+        public boolean pauseHardwareGeofence(int geofenceId) {
+            return native_pause_geofence(geofenceId);
+        }
+
+        public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
+            return native_resume_geofence(geofenceId, monitorTransition);
+        }
+    };
+
     private boolean deleteAidingData(Bundle extras) {
         int flags;
 
@@ -1017,6 +1051,7 @@
         return ((mEngineCapabilities & capability) != 0);
     }
 
+
     /**
      * called from native code to update our position.
      */
@@ -1320,6 +1355,73 @@
         sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
     }
 
+    /**
+     * Called from native to report GPS Geofence transition
+     * All geofence callbacks are called on the same thread
+     */
+    private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp, int transition, long transitionTimestamp) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGpsGeofenceTransition(geofenceId, flags, latitude, longitude,
+           altitude, speed, bearing, accuracy, timestamp, transition, transitionTimestamp);
+    }
+
+    /**
+     * called from native code to report GPS status change.
+     */
+    private void reportGeofenceStatus(int status, int flags, double latitude,
+            double longitude, double altitude, float speed, float bearing, float accuracy,
+            long timestamp) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGpsGeofenceStatus(status, flags, latitude, longitude, altitude,
+            speed, bearing, accuracy, timestamp);
+    }
+
+    /**
+     * called from native code - Geofence Add callback
+     */
+    private void reportGeofenceAddStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGpsGeofenceAddStatus(geofenceId, status);
+    }
+
+    /**
+     * called from native code - Geofence Remove callback
+     */
+    private void reportGeofenceRemoveStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGpsGeofenceRemoveStatus(geofenceId, status);
+    }
+
+    /**
+     * called from native code - Geofence Pause callback
+     */
+    private void reportGeofencePauseStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGpsGeofencePauseStatus(geofenceId, status);
+    }
+
+    /**
+     * called from native code - Geofence Resume callback
+     */
+    private void reportGeofenceResumeStatus(int geofenceId, int status) {
+        if (mGeofenceHardwareImpl == null) {
+            mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+        }
+        mGeofenceHardwareImpl.reportGpsGeofenceResumeStatus(geofenceId, status);
+    }
+
     //=============================================================
     // NI Client support
     //=============================================================
@@ -1650,4 +1752,13 @@
 
     private native void native_update_network_state(boolean connected, int type,
             boolean roaming, boolean available, String extraInfo, String defaultAPN);
+
+    // Hardware Geofence support.
+    private static native boolean native_is_geofence_supported();
+    private static native boolean native_add_geofence(int geofenceId, double latitude,
+            double longitude, double radius, int lastTransition,int monitorTransitions,
+            int notificationResponsivenes, int unknownTimer);
+    private static native boolean native_remove_geofence(int geofenceId);
+    private static native boolean native_resume_geofence(int geofenceId, int transitions);
+    private static native boolean native_pause_geofence(int geofenceId);
 }
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 3ae652a..a82f421 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -63,13 +63,13 @@
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
+import static com.android.internal.util.XmlUtils.readIntAttribute;
+import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
+import static com.android.internal.util.XmlUtils.writeIntAttribute;
+import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readIntAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readLongAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeBooleanAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeIntAttribute;
-import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.writeLongAttribute;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -149,7 +149,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.net.ProtocolException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -2088,44 +2087,4 @@
         }
         fout.print("]");
     }
-
-    public static class XmlUtils {
-        public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
-            final String value = in.getAttributeValue(null, name);
-            try {
-                return Integer.parseInt(value);
-            } catch (NumberFormatException e) {
-                throw new ProtocolException("problem parsing " + name + "=" + value + " as int");
-            }
-        }
-
-        public static void writeIntAttribute(XmlSerializer out, String name, int value)
-                throws IOException {
-            out.attribute(null, name, Integer.toString(value));
-        }
-
-        public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
-            final String value = in.getAttributeValue(null, name);
-            try {
-                return Long.parseLong(value);
-            } catch (NumberFormatException e) {
-                throw new ProtocolException("problem parsing " + name + "=" + value + " as long");
-            }
-        }
-
-        public static void writeLongAttribute(XmlSerializer out, String name, long value)
-                throws IOException {
-            out.attribute(null, name, Long.toString(value));
-        }
-
-        public static boolean readBooleanAttribute(XmlPullParser in, String name) {
-            final String value = in.getAttributeValue(null, name);
-            return Boolean.parseBoolean(value);
-        }
-
-        public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
-                throws IOException {
-            out.attribute(null, name, Boolean.toString(value));
-        }
-    }
 }
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 02a2c1b..d9c85bf 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -188,7 +188,7 @@
         }
     }
 
-    public int install(String name, int uid, int gid) {
+    public int install(String name, int uid, int gid, String seinfo) {
         StringBuilder builder = new StringBuilder("install");
         builder.append(' ');
         builder.append(name);
@@ -196,6 +196,8 @@
         builder.append(uid);
         builder.append(' ');
         builder.append(gid);
+        builder.append(' ');
+        builder.append(seinfo != null ? seinfo : "!");
         return execute(builder.toString());
     }
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 51f001f..cc9b785 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -110,8 +110,10 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.Environment.UserEnvironment;
+import android.os.UserManager;
+import android.provider.Settings.Secure;
+import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -170,7 +172,7 @@
 public class PackageManagerService extends IPackageManager.Stub {
     static final String TAG = "PackageManager";
     static final boolean DEBUG_SETTINGS = false;
-    static final boolean DEBUG_PREFERRED = true;
+    static final boolean DEBUG_PREFERRED = false;
     static final boolean DEBUG_UPGRADE = false;
     private static final boolean DEBUG_INSTALL = false;
     private static final boolean DEBUG_REMOVE = false;
@@ -339,9 +341,20 @@
     final SparseArray<HashSet<String>> mSystemPermissions =
             new SparseArray<HashSet<String>>();
 
+    static final class SharedLibraryEntry {
+        final String path;
+        final String apk;
+
+        SharedLibraryEntry(String _path, String _apk) {
+            path = _path;
+            apk = _apk;
+        }
+    }
+
     // These are the built-in shared libraries that were read from the
     // etc/permissions.xml file.
-    final HashMap<String, String> mSharedLibraries = new HashMap<String, String>();
+    final HashMap<String, SharedLibraryEntry> mSharedLibraries
+            = new HashMap<String, SharedLibraryEntry>();
 
     // Temporary for building the final shared libraries for an .apk.
     String[] mTmpSharedLibraries = null;
@@ -351,6 +364,9 @@
     final HashMap<String, FeatureInfo> mAvailableFeatures =
             new HashMap<String, FeatureInfo>();
 
+    // If mac_permissions.xml was found for seinfo labeling.
+    boolean mFoundPolicyFile;
+
     // All available activities, for your resolving pleasure.
     final ActivityIntentResolver mActivities =
             new ActivityIntentResolver();
@@ -390,8 +406,7 @@
     final SparseArray<PackageVerificationState> mPendingVerification
             = new SparseArray<PackageVerificationState>();
 
-    final ArrayList<PackageParser.Package> mDeferredDexOpt =
-            new ArrayList<PackageParser.Package>();
+    HashSet<PackageParser.Package> mDeferredDexOpt = null;
 
     /** Token for keys in mPendingVerification. */
     private int mPendingVerificationToken = 0;
@@ -514,10 +529,9 @@
         void doHandleMessage(Message msg) {
             switch (msg.what) {
                 case INIT_COPY: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy");
                     HandlerParams params = (HandlerParams) msg.obj;
                     int idx = mPendingInstalls.size();
-                    if (DEBUG_INSTALL) Slog.i(TAG, "idx=" + idx);
+                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
                     // If a bind was already initiated we dont really
                     // need to do anything. The pending install
                     // will be processed later on.
@@ -1020,8 +1034,11 @@
 
             readPermissions();
 
+            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
+
             mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                     mSdkVersion, mOnlyCore);
+
             long startTime = SystemClock.uptimeMillis();
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -1071,9 +1088,12 @@
              * Also ensure all external libraries have had dexopt run on them.
              */
             if (mSharedLibraries.size() > 0) {
-                Iterator<String> libs = mSharedLibraries.values().iterator();
+                Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator();
                 while (libs.hasNext()) {
-                    String lib = libs.next();
+                    String lib = libs.next().path;
+                    if (lib == null) {
+                        continue;
+                    }
                     try {
                         if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
                             libFiles.add(lib);
@@ -1277,6 +1297,10 @@
                 mDrmAppInstallObserver = null;
             }
 
+            // Now that we know all of the shared libraries, update all clients to have
+            // the correct library paths.
+            updateAllSharedLibrariesLPw();
+
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
             Slog.i(TAG, "Time to scan packages: "
@@ -1301,6 +1325,12 @@
                             ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
                             : 0));
 
+            // If this is the first boot, and it is a normal boot, then
+            // we need to initialize the default preferred apps.
+            if (!mRestoredSettings && !onlyCore) {
+                mSettings.readDefaultPreferredAppsLPw(this, 0);
+            }
+
             // can downgrade to reader
             mSettings.writeLPr();
 
@@ -1517,7 +1547,7 @@
                                 + parser.getPositionDescription());
                     } else {
                         //Log.i(TAG, "Got library " + lname + " in " + lfile);
-                        mSharedLibraries.put(lname, lfile);
+                        mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null));
                     }
                     XmlUtils.skipCurrentTag(parser);
                     continue;
@@ -2220,6 +2250,34 @@
         }
     }
 
+    private static void checkGrantRevokePermissions(PackageParser.Package pkg, BasePermission bp) {
+        int index = pkg.requestedPermissions.indexOf(bp.name);
+        if (index == -1) {
+            throw new SecurityException("Package " + pkg.packageName
+                    + " has not requested permission " + bp.name);
+        }
+        boolean isNormal =
+                ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE)
+                        == PermissionInfo.PROTECTION_NORMAL);
+        boolean isDangerous =
+                ((bp.protectionLevel&PermissionInfo.PROTECTION_MASK_BASE)
+                        == PermissionInfo.PROTECTION_DANGEROUS);
+        boolean isDevelopment =
+                ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0);
+
+        if (!isNormal && !isDangerous && !isDevelopment) {
+            throw new SecurityException("Permission " + bp.name
+                    + " is not a changeable permission type");
+        }
+
+        if (isNormal || isDangerous) {
+            if (pkg.requestedPermissionsRequired.get(index)) {
+                throw new SecurityException("Can't change " + bp.name
+                        + ". It is required by the application");
+            }
+        }
+    }
+
     public void grantPermission(String packageName, String permissionName) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
@@ -2230,21 +2288,16 @@
             }
             final BasePermission bp = mSettings.mPermissions.get(permissionName);
             if (bp == null) {
-                throw new IllegalArgumentException("Unknown permission: " + packageName);
+                throw new IllegalArgumentException("Unknown permission: " + permissionName);
             }
-            if (!pkg.requestedPermissions.contains(permissionName)) {
-                throw new SecurityException("Package " + packageName
-                        + " has not requested permission " + permissionName);
-            }
-            if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) {
-                throw new SecurityException("Permission " + permissionName
-                        + " is not a development permission");
-            }
+
+            checkGrantRevokePermissions(pkg, bp);
+
             final PackageSetting ps = (PackageSetting) pkg.mExtras;
             if (ps == null) {
                 return;
             }
-            final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+            final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps;
             if (gp.grantedPermissions.add(permissionName)) {
                 if (ps.haveGids) {
                     gp.gids = appendInts(gp.gids, bp.gids);
@@ -2255,6 +2308,8 @@
     }
 
     public void revokePermission(String packageName, String permissionName) {
+        int changedAppId = -1;
+
         synchronized (mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             if (pkg == null) {
@@ -2266,27 +2321,46 @@
             }
             final BasePermission bp = mSettings.mPermissions.get(permissionName);
             if (bp == null) {
-                throw new IllegalArgumentException("Unknown permission: " + packageName);
+                throw new IllegalArgumentException("Unknown permission: " + permissionName);
             }
-            if (!pkg.requestedPermissions.contains(permissionName)) {
-                throw new SecurityException("Package " + packageName
-                        + " has not requested permission " + permissionName);
-            }
-            if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) {
-                throw new SecurityException("Permission " + permissionName
-                        + " is not a development permission");
-            }
+
+            checkGrantRevokePermissions(pkg, bp);
+
             final PackageSetting ps = (PackageSetting) pkg.mExtras;
             if (ps == null) {
                 return;
             }
-            final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+            final GrantedPermissions gp = (ps.sharedUser != null) ? ps.sharedUser : ps;
             if (gp.grantedPermissions.remove(permissionName)) {
                 gp.grantedPermissions.remove(permissionName);
                 if (ps.haveGids) {
                     gp.gids = removeInts(gp.gids, bp.gids);
                 }
                 mSettings.writeLPr();
+                changedAppId = ps.appId;
+            }
+        }
+
+        if (changedAppId >= 0) {
+            // We changed the perm on someone, kill its processes.
+            IActivityManager am = ActivityManagerNative.getDefault();
+            if (am != null) {
+                final int callingUserId = UserHandle.getCallingUserId();
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    //XXX we should only revoke for the calling user's app permissions,
+                    // but for now we impact all users.
+                    //am.killUid(UserHandle.getUid(callingUserId, changedAppId),
+                    //        "revoke " + permissionName);
+                    int[] users = sUserManager.getUserIds();
+                    for (int user : users) {
+                        am.killUid(UserHandle.getUid(user, changedAppId),
+                                "revoke " + permissionName);
+                    }
+                } catch (RemoteException e) {
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
         }
     }
@@ -3249,6 +3323,7 @@
             int parseFlags, int scanMode, long currentTime, UserHandle user) {
         mLastScanError = PackageManager.INSTALL_SUCCEEDED;
         String scanPath = scanFile.getPath();
+        if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath);
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser(scanPath);
         pp.setSeparateProcesses(mSeparateProcesses);
@@ -3278,6 +3353,7 @@
             // package.  Must look for it either under the original or real
             // package name depending on our state.
             updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName);
+            if (DEBUG_INSTALL && updatedPkg != null) Slog.d(TAG, "updatedPkg = " + updatedPkg);
         }
         // First check if this is a system package that may involve an update
         if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
@@ -3285,6 +3361,7 @@
                 // The path has changed from what was last scanned...  check the
                 // version of the new path against what we have stored to determine
                 // what to do.
+                if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
                 if (pkg.mVersionCode < ps.versionCode) {
                     // The system package has been updated and the code path does not match
                     // Ignore entry. Skip it.
@@ -3298,6 +3375,7 @@
                         updatedPkg.codePath = scanFile;
                         updatedPkg.codePathString = scanFile.toString();                        
                     }
+                    updatedPkg.pkg = pkg;
                     mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
                     return null;
                 } else {
@@ -3353,6 +3431,7 @@
              */
             if (compareSignatures(ps.signatures.mSignatures, pkg.mSignatures)
                     != PackageManager.SIGNATURE_MATCH) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Signature mismatch!");
                 deletePackageLI(pkg.packageName, null, true, 0, null, false);
                 ps = null;
             } else {
@@ -3484,28 +3563,28 @@
     }
 
     public void performBootDexOpt() {
-        ArrayList<PackageParser.Package> pkgs = null;
+        HashSet<PackageParser.Package> pkgs = null;
         synchronized (mPackages) {
-            if (mDeferredDexOpt.size() > 0) {
-                pkgs = new ArrayList<PackageParser.Package>(mDeferredDexOpt);
-                mDeferredDexOpt.clear();
-            }
+            pkgs = mDeferredDexOpt;
+            mDeferredDexOpt = null;
         }
         if (pkgs != null) {
-            for (int i=0; i<pkgs.size(); i++) {
+            int i = 0;
+            for (PackageParser.Package pkg : pkgs) {
                 if (!isFirstBoot()) {
+                    i++;
                     try {
                         ActivityManagerNative.getDefault().showBootMessage(
                                 mContext.getResources().getString(
                                         com.android.internal.R.string.android_upgrading_apk,
-                                        i+1, pkgs.size()), true);
+                                        i, pkgs.size()), true);
                     } catch (RemoteException e) {
                     }
                 }
-                PackageParser.Package p = pkgs.get(i);
+                PackageParser.Package p = pkg;
                 synchronized (mInstallLock) {
                     if (!p.mDidDexOpt) {
-                        performDexOptLI(p, false, false);
+                        performDexOptLI(p, false, false, true);
                     }
                 }
             }
@@ -3527,7 +3606,27 @@
             }
         }
         synchronized (mInstallLock) {
-            return performDexOptLI(p, false, false) == DEX_OPT_PERFORMED;
+            return performDexOptLI(p, false, false, true) == DEX_OPT_PERFORMED;
+        }
+    }
+
+    private void performDexOptLibsLI(ArrayList<String> libs, boolean forceDex, boolean defer,
+            HashSet<String> done) {
+        for (int i=0; i<libs.size(); i++) {
+            PackageParser.Package libPkg;
+            String libName;
+            synchronized (mPackages) {
+                libName = libs.get(i);
+                SharedLibraryEntry lib = mSharedLibraries.get(libName);
+                if (lib != null && lib.apk != null) {
+                    libPkg = mPackages.get(lib.apk);
+                } else {
+                    libPkg = null;
+                }
+            }
+            if (libPkg != null && !done.contains(libName)) {
+                performDexOptLI(libPkg, forceDex, defer, done);
+            }
         }
     }
 
@@ -3536,14 +3635,27 @@
     static final int DEX_OPT_DEFERRED = 2;
     static final int DEX_OPT_FAILED = -1;
 
-    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer) {
+    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer,
+            HashSet<String> done) {
         boolean performed = false;
+        if (done != null) {
+            done.add(pkg.packageName);
+            if (pkg.usesLibraries != null) {
+                performDexOptLibsLI(pkg.usesLibraries, forceDex, defer, done);
+            }
+            if (pkg.usesOptionalLibraries != null) {
+                performDexOptLibsLI(pkg.usesOptionalLibraries, forceDex, defer, done);
+            }
+        }
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             String path = pkg.mScanPath;
             int ret = 0;
             try {
                 if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) {
                     if (!forceDex && defer) {
+                        if (mDeferredDexOpt == null) {
+                            mDeferredDexOpt = new HashSet<PackageParser.Package>();
+                        }
                         mDeferredDexOpt.add(pkg);
                         return DEX_OPT_DEFERRED;
                     } else {
@@ -3576,6 +3688,19 @@
         return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
     }
 
+    private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer,
+            boolean inclDependencies) {
+        HashSet<String> done;
+        boolean performed = false;
+        if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
+            done = new HashSet<String>();
+            done.add(pkg.packageName);
+        } else {
+            done = null;
+        }
+        return performDexOptLI(pkg, forceDex, defer, done);
+    }
+
     private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
         if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -3609,9 +3734,9 @@
         }
     }
 
-    private int createDataDirsLI(String packageName, int uid) {
+    private int createDataDirsLI(String packageName, int uid, String seinfo) {
         int[] users = sUserManager.getUserIds();
-        int res = mInstaller.install(packageName, uid, uid);
+        int res = mInstaller.install(packageName, uid, uid, seinfo);
         if (res < 0) {
             return res;
         }
@@ -3646,6 +3771,113 @@
         return res;
     }
 
+    private int addSharedLibraryLPw(final SharedLibraryEntry file, int num,
+            PackageParser.Package changingLib) {
+        if (file.path != null) {
+            mTmpSharedLibraries[num] = file.path;
+            return num+1;
+        }
+        PackageParser.Package p = mPackages.get(file.apk);
+        if (changingLib != null && changingLib.packageName.equals(file.apk)) {
+            // If we are doing this while in the middle of updating a library apk,
+            // then we need to make sure to use that new apk for determining the
+            // dependencies here.  (We haven't yet finished committing the new apk
+            // to the package manager state.)
+            if (p == null || p.packageName.equals(changingLib.packageName)) {
+                p = changingLib;
+            }
+        }
+        if (p != null) {
+            String path = p.mPath;
+            for (int i=0; i<num; i++) {
+                if (mTmpSharedLibraries[i].equals(path)) {
+                    return num;
+                }
+            }
+            mTmpSharedLibraries[num] = p.mPath;
+            return num+1;
+        }
+        return num;
+    }
+
+    private boolean updateSharedLibrariesLPw(PackageParser.Package pkg,
+            PackageParser.Package changingLib) {
+        if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
+            if (mTmpSharedLibraries == null ||
+                    mTmpSharedLibraries.length < mSharedLibraries.size()) {
+                mTmpSharedLibraries = new String[mSharedLibraries.size()];
+            }
+            int num = 0;
+            int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
+            for (int i=0; i<N; i++) {
+                final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i));
+                if (file == null) {
+                    Slog.e(TAG, "Package " + pkg.packageName
+                            + " requires unavailable shared library "
+                            + pkg.usesLibraries.get(i) + "; failing!");
+                    mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
+                    return false;
+                }
+                num = addSharedLibraryLPw(file, num, changingLib);
+            }
+            N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
+            for (int i=0; i<N; i++) {
+                final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
+                if (file == null) {
+                    Slog.w(TAG, "Package " + pkg.packageName
+                            + " desires unavailable shared library "
+                            + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
+                } else {
+                    num = addSharedLibraryLPw(file, num, changingLib);
+                }
+            }
+            if (num > 0) {
+                pkg.usesLibraryFiles = new String[num];
+                System.arraycopy(mTmpSharedLibraries, 0,
+                        pkg.usesLibraryFiles, 0, num);
+            } else {
+                pkg.usesLibraryFiles = null;
+            }
+        }
+        return true;
+    }
+
+    private static boolean hasString(List<String> list, List<String> which) {
+        if (list == null) {
+            return false;
+        }
+        for (int i=list.size()-1; i>=0; i--) {
+            for (int j=which.size()-1; j>=0; j--) {
+                if (which.get(j).equals(list.get(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private void updateAllSharedLibrariesLPw() {
+        for (PackageParser.Package pkg : mPackages.values()) {
+            updateSharedLibrariesLPw(pkg, null);
+        }
+    }
+
+    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
+            PackageParser.Package changingPkg) {
+        ArrayList<PackageParser.Package> res = null;
+        for (PackageParser.Package pkg : mPackages.values()) {
+            if (hasString(pkg.usesLibraries, changingPkg.libraryNames)
+                    || hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)) {
+                if (res == null) {
+                    res = new ArrayList<PackageParser.Package>();
+                }
+                res.add(pkg);
+                updateSharedLibrariesLPw(pkg, changingPkg);
+            }
+        }
+        return res;
+    }
+
     private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
             int parseFlags, int scanMode, long currentTime, UserHandle user) {
         File scanFile = new File(pkg.mScanPath);
@@ -3725,42 +3957,14 @@
 
         // writer
         synchronized (mPackages) {
-            // Check all shared libraries and map to their actual file path.
-            if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
-                if (mTmpSharedLibraries == null ||
-                        mTmpSharedLibraries.length < mSharedLibraries.size()) {
-                    mTmpSharedLibraries = new String[mSharedLibraries.size()];
-                }
-                int num = 0;
-                int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
-                for (int i=0; i<N; i++) {
-                    final String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
-                    if (file == null) {
-                        Slog.e(TAG, "Package " + pkg.packageName
-                                + " requires unavailable shared library "
-                                + pkg.usesLibraries.get(i) + "; failing!");
-                        mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
-                        return null;
-                    }
-                    mTmpSharedLibraries[num] = file;
-                    num++;
-                }
-                N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
-                for (int i=0; i<N; i++) {
-                    final String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
-                    if (file == null) {
-                        Slog.w(TAG, "Package " + pkg.packageName
-                                + " desires unavailable shared library "
-                                + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
-                    } else {
-                        mTmpSharedLibraries[num] = file;
-                        num++;
-                    }
-                }
-                if (num > 0) {
-                    pkg.usesLibraryFiles = new String[num];
-                    System.arraycopy(mTmpSharedLibraries, 0,
-                            pkg.usesLibraryFiles, 0, num);
+            if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+                // Check all shared libraries and map to their actual file path.
+                // We only do this here for apps not on a system dir, because those
+                // are the only ones that can fail an install due to this.  We
+                // will take care of the system apps by updating all of their
+                // library paths after the scan is done.
+                if (!updateSharedLibrariesLPw(pkg, null)) {
+                    return null;
                 }
             }
 
@@ -3874,6 +4078,10 @@
                 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
 
+            if (mFoundPolicyFile) {
+                SELinuxMMAC.assignSeinfoValue(pkg);
+            }
+
             pkg.applicationInfo.uid = pkgSetting.appId;
             pkg.mExtras = pkgSetting;
 
@@ -4012,7 +4220,8 @@
                             recovered = true;
 
                             // And now re-install the app.
-                            ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
+                            ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,
+                                                   pkg.applicationInfo.seinfo);
                             if (ret == -1) {
                                 // Ack should not happen!
                                 msg = prefix + pkg.packageName
@@ -4058,7 +4267,8 @@
                         Log.v(TAG, "Want this data dir: " + dataPath);
                 }
                 //invoke installer to do the actual installation
-                int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid);
+                int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid,
+                                           pkg.applicationInfo.seinfo);
                 if (ret < 0) {
                     // Error from installer
                     mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -4166,7 +4376,7 @@
         pkg.mScanPath = path;
 
         if ((scanMode&SCAN_NO_DEX) == 0) {
-            if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0)
+            if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
                     == DEX_OPT_FAILED) {
                 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
                 return null;
@@ -4178,6 +4388,80 @@
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
         }
 
+        ArrayList<PackageParser.Package> clientLibPkgs = null;
+
+        // writer
+        synchronized (mPackages) {
+            if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+                // Only system apps can add new shared libraries.
+                if (pkg.libraryNames != null) {
+                    for (int i=0; i<pkg.libraryNames.size(); i++) {
+                        String name = pkg.libraryNames.get(i);
+                        boolean allowed = false;
+                        if (isUpdatedSystemApp(pkg)) {
+                            // New library entries can only be added through the
+                            // system image.  This is important to get rid of a lot
+                            // of nasty edge cases: for example if we allowed a non-
+                            // system update of the app to add a library, then uninstalling
+                            // the update would make the library go away, and assumptions
+                            // we made such as through app install filtering would now
+                            // have allowed apps on the device which aren't compatible
+                            // with it.  Better to just have the restriction here, be
+                            // conservative, and create many fewer cases that can negatively
+                            // impact the user experience.
+                            final PackageSetting sysPs = mSettings
+                                    .getDisabledSystemPkgLPr(pkg.packageName);
+                            if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
+                                for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) {
+                                    if (name.equals(sysPs.pkg.libraryNames.get(j))) {
+                                        allowed = true;
+                                        allowed = true;
+                                        break;
+                                    }
+                                }
+                            }
+                        } else {
+                            allowed = true;
+                        }
+                        if (allowed) {
+                            if (!mSharedLibraries.containsKey(name)) {
+                                mSharedLibraries.put(name, new SharedLibraryEntry(null,
+                                        pkg.packageName));
+                            } else if (!name.equals(pkg.packageName)) {
+                                Slog.w(TAG, "Package " + pkg.packageName + " library "
+                                        + name + " already exists; skipping");
+                            }
+                        } else {
+                            Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
+                                    + name + " that is not declared on system image; skipping");
+                        }
+                    }
+                    if ((scanMode&SCAN_BOOTING) == 0) {
+                        // If we are not booting, we need to update any applications
+                        // that are clients of our shared library.  If we are booting,
+                        // this will all be done once the scan is complete.
+                        clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
+                    }
+                }
+            }
+        }
+
+        // We also need to dexopt any apps that are dependent on this library.  Note that
+        // if these fail, we should abort the install since installing the library will
+        // result in some apps being broken.
+        if (clientLibPkgs != null) {
+            if ((scanMode&SCAN_NO_DEX) == 0) {
+                for (int i=0; i<clientLibPkgs.size(); i++) {
+                    PackageParser.Package clientPkg = clientLibPkgs.get(i);
+                    if (performDexOptLI(clientPkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
+                            == DEX_OPT_FAILED) {
+                        mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
+                        return null;
+                    }
+                }
+            }
+        }
+
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
         // version of the application while the new one gets installed.
@@ -4186,6 +4470,15 @@
                         pkg.applicationInfo.uid);
         }
 
+        // Also need to kill any apps that are dependent on the library.
+        if (clientLibPkgs != null) {
+            for (int i=0; i<clientLibPkgs.size(); i++) {
+                PackageParser.Package clientPkg = clientLibPkgs.get(i);
+                killApplication(clientPkg.applicationInfo.packageName,
+                        clientPkg.applicationInfo.uid);
+            }
+        }
+
         // writer
         synchronized (mPackages) {
             // We don't expect installation to fail beyond this point,
@@ -4591,7 +4884,7 @@
                     }
                 }
             }
-            if (chatty) {
+            if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
                     r = new StringBuilder(256);
                 } else {
@@ -4627,7 +4920,7 @@
         for (i=0; i<N; i++) {
             PackageParser.Activity a = pkg.receivers.get(i);
             mReceivers.removeActivity(a, "receiver");
-            if (chatty) {
+            if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
                     r = new StringBuilder(256);
                 } else {
@@ -4645,7 +4938,7 @@
         for (i=0; i<N; i++) {
             PackageParser.Activity a = pkg.activities.get(i);
             mActivities.removeActivity(a, "activity");
-            if (chatty) {
+            if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
                     r = new StringBuilder(256);
                 } else {
@@ -4668,7 +4961,7 @@
             }
             if (bp != null && bp.perm == p) {
                 bp.perm = null;
-                if (chatty) {
+                if (DEBUG_REMOVE && chatty) {
                     if (r == null) {
                         r = new StringBuilder(256);
                     } else {
@@ -4687,7 +4980,7 @@
         for (i=0; i<N; i++) {
             PackageParser.Instrumentation a = pkg.instrumentation.get(i);
             mInstrumentation.remove(a.getComponentName());
-            if (chatty) {
+            if (DEBUG_REMOVE && chatty) {
                 if (r == null) {
                     r = new StringBuilder(256);
                 } else {
@@ -4699,6 +4992,31 @@
         if (r != null) {
             if (DEBUG_REMOVE) Log.d(TAG, "  Instrumentation: " + r);
         }
+
+        r = null;
+        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+            // Only system apps can hold shared libraries.
+            if (pkg.libraryNames != null) {
+                for (i=0; i<pkg.libraryNames.size(); i++) {
+                    String name = pkg.libraryNames.get(i);
+                    SharedLibraryEntry cur = mSharedLibraries.get(name);
+                    if (cur != null && cur.apk != null && cur.apk.equals(pkg.packageName)) {
+                        mSharedLibraries.remove(name);
+                        if (DEBUG_REMOVE && chatty) {
+                            if (r == null) {
+                                r = new StringBuilder(256);
+                            } else {
+                                r.append(' ');
+                            }
+                            r.append(name);
+                        }
+                    }
+                }
+            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Libraries: " + r);
+        }
     }
 
     private static final boolean isPackageFilename(String name) {
@@ -4823,134 +5141,97 @@
         final int N = pkg.requestedPermissions.size();
         for (int i=0; i<N; i++) {
             final String name = pkg.requestedPermissions.get(i);
-            //final boolean required = pkg.requestedPermssionsRequired.get(i);
+            final boolean required = pkg.requestedPermissionsRequired.get(i);
             final BasePermission bp = mSettings.mPermissions.get(name);
             if (DEBUG_INSTALL) {
                 if (gp != ps) {
                     Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
                 }
             }
-            if (bp != null && bp.packageSetting != null) {
-                final String perm = bp.name;
-                boolean allowed;
-                boolean allowedSig = false;
-                final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
-                if (level == PermissionInfo.PROTECTION_NORMAL
-                        || level == PermissionInfo.PROTECTION_DANGEROUS) {
-                    allowed = true;
-                } else if (bp.packageSetting == null) {
-                    // This permission is invalid; skip it.
-                    allowed = false;
-                } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
-                    allowed = (compareSignatures(
-                            bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
-                                    == PackageManager.SIGNATURE_MATCH)
-                            || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
-                                    == PackageManager.SIGNATURE_MATCH);
-                    if (!allowed && (bp.protectionLevel
-                            & PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
-                        if (isSystemApp(pkg)) {
-                            // For updated system applications, a system permission
-                            // is granted only if it had been defined by the original application.
-                            if (isUpdatedSystemApp(pkg)) {
-                                final PackageSetting sysPs = mSettings
-                                        .getDisabledSystemPkgLPr(pkg.packageName);
-                                final GrantedPermissions origGp = sysPs.sharedUser != null
-                                        ? sysPs.sharedUser : sysPs;
-                                if (origGp.grantedPermissions.contains(perm)) {
-                                    allowed = true;
-                                } else {
-                                    allowed = false;
-                                }
-                            } else {
-                                allowed = true;
-                            }
-                        }
-                    }
-                    if (!allowed && (bp.protectionLevel
-                            & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
-                        // For development permissions, a development permission
-                        // is granted only if it was already granted.
-                        if (origPermissions.contains(perm)) {
-                            allowed = true;
-                        } else {
-                            allowed = false;
-                        }
-                    }
-                    if (allowed) {
-                        allowedSig = true;
-                    }
-                } else {
-                    allowed = false;
+
+            if (bp == null || bp.packageSetting == null) {
+                Slog.w(TAG, "Unknown permission " + name
+                        + " in package " + pkg.packageName);
+                continue;
+            }
+
+            final String perm = bp.name;
+            boolean allowed;
+            boolean allowedSig = false;
+            final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+            if (level == PermissionInfo.PROTECTION_NORMAL
+                    || level == PermissionInfo.PROTECTION_DANGEROUS) {
+                // We grant a normal or dangerous permission if any of the following
+                // are true:
+                // 1) The permission is required
+                // 2) The permission is optional, but was granted in the past
+                // 3) The permission is optional, but was requested by an
+                //    app in /system (not /data)
+                //
+                // Otherwise, reject the permission.
+                allowed = (required || origPermissions.contains(perm)
+                        || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
+            } else if (bp.packageSetting == null) {
+                // This permission is invalid; skip it.
+                allowed = false;
+            } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
+                allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
+                if (allowed) {
+                    allowedSig = true;
                 }
-                if (DEBUG_INSTALL) {
-                    if (gp != ps) {
-                        Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
+            } else {
+                allowed = false;
+            }
+            if (DEBUG_INSTALL) {
+                if (gp != ps) {
+                    Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
+                }
+            }
+            if (allowed) {
+                if (!isSystemApp(ps) && ps.permissionsFixed) {
+                    // If this is an existing, non-system package, then
+                    // we can't add any new permissions to it.
+                    if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
+                        // Except...  if this is a permission that was added
+                        // to the platform (note: need to only do this when
+                        // updating the platform).
+                        allowed = isNewPlatformPermissionForPackage(perm, pkg);
                     }
                 }
                 if (allowed) {
-                    if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0
-                            && ps.permissionsFixed) {
-                        // If this is an existing, non-system package, then
-                        // we can't add any new permissions to it.
-                        if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
-                            allowed = false;
-                            // Except...  if this is a permission that was added
-                            // to the platform (note: need to only do this when
-                            // updating the platform).
-                            final int NP = PackageParser.NEW_PERMISSIONS.length;
-                            for (int ip=0; ip<NP; ip++) {
-                                final PackageParser.NewPermissionInfo npi
-                                        = PackageParser.NEW_PERMISSIONS[ip];
-                                if (npi.name.equals(perm)
-                                        && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
-                                    allowed = true;
-                                    Log.i(TAG, "Auto-granting " + perm + " to old pkg "
-                                            + pkg.packageName);
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                    if (allowed) {
-                        if (!gp.grantedPermissions.contains(perm)) {
-                            changedPermission = true;
-                            gp.grantedPermissions.add(perm);
-                            gp.gids = appendInts(gp.gids, bp.gids);
-                        } else if (!ps.haveGids) {
-                            gp.gids = appendInts(gp.gids, bp.gids);
-                        }
-                    } else {
-                        Slog.w(TAG, "Not granting permission " + perm
-                                + " to package " + pkg.packageName
-                                + " because it was previously installed without");
+                    if (!gp.grantedPermissions.contains(perm)) {
+                        changedPermission = true;
+                        gp.grantedPermissions.add(perm);
+                        gp.gids = appendInts(gp.gids, bp.gids);
+                    } else if (!ps.haveGids) {
+                        gp.gids = appendInts(gp.gids, bp.gids);
                     }
                 } else {
-                    if (gp.grantedPermissions.remove(perm)) {
-                        changedPermission = true;
-                        gp.gids = removeInts(gp.gids, bp.gids);
-                        Slog.i(TAG, "Un-granting permission " + perm
-                                + " from package " + pkg.packageName
-                                + " (protectionLevel=" + bp.protectionLevel
-                                + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
-                                + ")");
-                    } else {
-                        Slog.w(TAG, "Not granting permission " + perm
-                                + " to package " + pkg.packageName
-                                + " (protectionLevel=" + bp.protectionLevel
-                                + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
-                                + ")");
-                    }
+                    Slog.w(TAG, "Not granting permission " + perm
+                            + " to package " + pkg.packageName
+                            + " because it was previously installed without");
                 }
             } else {
-                Slog.w(TAG, "Unknown permission " + name
-                        + " in package " + pkg.packageName);
+                if (gp.grantedPermissions.remove(perm)) {
+                    changedPermission = true;
+                    gp.gids = removeInts(gp.gids, bp.gids);
+                    Slog.i(TAG, "Un-granting permission " + perm
+                            + " from package " + pkg.packageName
+                            + " (protectionLevel=" + bp.protectionLevel
+                            + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+                            + ")");
+                } else {
+                    Slog.w(TAG, "Not granting permission " + perm
+                            + " to package " + pkg.packageName
+                            + " (protectionLevel=" + bp.protectionLevel
+                            + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+                            + ")");
+                }
             }
         }
 
         if ((changedPermission || replace) && !ps.permissionsFixed &&
-                ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) ||
-                ((ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)){
+                !isSystemApp(ps) || isUpdatedSystemApp(ps)){
             // This is the first that we have heard about this package, so the
             // permissions we have now selected are fixed until explicitly
             // changed.
@@ -4958,7 +5239,77 @@
         }
         ps.haveGids = true;
     }
-    
+
+    private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
+        boolean allowed = false;
+        final int NP = PackageParser.NEW_PERMISSIONS.length;
+        for (int ip=0; ip<NP; ip++) {
+            final PackageParser.NewPermissionInfo npi
+                    = PackageParser.NEW_PERMISSIONS[ip];
+            if (npi.name.equals(perm)
+                    && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) {
+                allowed = true;
+                Log.i(TAG, "Auto-granting " + perm + " to old pkg "
+                        + pkg.packageName);
+                break;
+            }
+        }
+        return allowed;
+    }
+
+    private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
+                                          BasePermission bp, HashSet<String> origPermissions) {
+        boolean allowed;
+        allowed = (compareSignatures(
+                bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
+                        == PackageManager.SIGNATURE_MATCH)
+                || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
+                        == PackageManager.SIGNATURE_MATCH);
+        if (!allowed && (bp.protectionLevel
+                & PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {
+            if (isSystemApp(pkg)) {
+                // For updated system applications, a system permission
+                // is granted only if it had been defined by the original application.
+                if (isUpdatedSystemApp(pkg)) {
+                    final PackageSetting sysPs = mSettings
+                            .getDisabledSystemPkgLPr(pkg.packageName);
+                    final GrantedPermissions origGp = sysPs.sharedUser != null
+                            ? sysPs.sharedUser : sysPs;
+                    if (origGp.grantedPermissions.contains(perm)) {
+                        allowed = true;
+                    } else {
+                        // The system apk may have been updated with an older
+                        // version of the one on the data partition, but which
+                        // granted a new system permission that it didn't have
+                        // before.  In this case we do want to allow the app to
+                        // now get the new permission, because it is allowed by
+                        // the system image.
+                        allowed = false;
+                        if (sysPs.pkg != null) {
+                            for (int j=0;
+                                    j<sysPs.pkg.requestedPermissions.size(); j++) {
+                                if (perm.equals(
+                                        sysPs.pkg.requestedPermissions.get(j))) {
+                                    allowed = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    allowed = true;
+                }
+            }
+        }
+        if (!allowed && (bp.protectionLevel
+                & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {
+            // For development permissions, a development permission
+            // is granted only if it was already granted.
+            allowed = origPermissions.contains(perm);
+        }
+        return allowed;
+    }
+
     final class ActivityIntentResolver
             extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
         public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
@@ -5085,8 +5436,9 @@
         }
 
         @Override
-        protected String packageForFilter(PackageParser.ActivityIntentInfo info) {
-            return info.activity.owner.packageName;
+        protected boolean isPackageForFilter(String packageName,
+                PackageParser.ActivityIntentInfo info) {
+            return packageName.equals(info.activity.owner.packageName);
         }
         
         @Override
@@ -5282,8 +5634,9 @@
         }
 
         @Override
-        protected String packageForFilter(PackageParser.ServiceIntentInfo info) {
-            return info.service.owner.packageName;
+        protected boolean isPackageForFilter(String packageName,
+                PackageParser.ServiceIntentInfo info) {
+            return packageName.equals(info.service.owner.packageName);
         }
         
         @Override
@@ -5557,6 +5910,7 @@
                 }
                 if ((event&REMOVE_EVENTS) != 0) {
                     if (ps != null) {
+                        if (DEBUG_REMOVE) Slog.d(TAG, "Package disappeared: " + ps);
                         removePackageLI(ps, true);
                         removedPackage = ps.name;
                         removedAppId = ps.appId;
@@ -5565,6 +5919,7 @@
 
                 if ((event&ADD_EVENTS) != 0) {
                     if (p == null) {
+                        if (DEBUG_INSTALL) Slog.d(TAG, "New file appeared: " + fullPath);
                         p = scanPackageLI(fullPath,
                                 (mIsRom ? PackageParser.PARSE_IS_SYSTEM
                                         | PackageParser.PARSE_IS_SYSTEM_DIR: 0) |
@@ -5645,7 +6000,7 @@
                 null);
 
         final int uid = Binder.getCallingUid();
-        if (!isUserAllowed(UserHandle.getUserId(uid), UserManager.ALLOW_INSTALL_APPS)) {
+        if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) {
             try {
                 observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
             } catch (RemoteException re) {
@@ -5693,7 +6048,7 @@
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     "installExistingPackage for user " + userId);
         }
-        if (!isUserAllowed(userId, UserManager.ALLOW_INSTALL_APPS)) {
+        if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
 
@@ -5727,13 +6082,13 @@
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
-    private boolean isUserAllowed(int userId, String restrictionKey) {
+    private boolean isUserRestricted(int userId, String restrictionKey) {
         Bundle restrictions = sUserManager.getUserRestrictions(userId);
-        if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) {
-            Log.w(TAG, "User does not have permission to: " + restrictionKey);
-            return false;
+        if (restrictions.getBoolean(restrictionKey, false)) {
+            Log.w(TAG, "User is restricted: " + restrictionKey);
+            return true;
         }
-        return true;
+        return false;
     }
 
     @Override
@@ -6126,7 +6481,7 @@
         final boolean startCopy() {
             boolean res;
             try {
-                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy");
+                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
 
                 if (++mRetries > MAX_RETRIES) {
                     Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
@@ -6170,6 +6525,13 @@
         }
 
         @Override
+        public String toString() {
+            return "MeasureParams{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + mStats.packageName + "}";
+        }
+
+        @Override
         void handleStartCopy() throws RemoteException {
             synchronized (mInstallLock) {
                 mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
@@ -6258,6 +6620,13 @@
             this.encryptionParams = encryptionParams;
         }
 
+        @Override
+        public String toString() {
+            return "InstallParams{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + mPackageURI + "}";
+        }
+
         public ManifestDigest getManifestDigest() {
             if (verificationParams == null) {
                 return null;
@@ -6671,6 +7040,13 @@
             }
         }
 
+        @Override
+        public String toString() {
+            return "MoveParams{"
+                + Integer.toHexString(System.identityHashCode(this))
+                + " " + packageName + "}";
+        }
+
         public void handleStartCopy() throws RemoteException {
             mRet = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
             // Check for storage space on target medium
@@ -7582,6 +7958,7 @@
         // Remember this for later, in case we need to rollback this install
         String pkgName = pkg.packageName;
 
+        if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
         boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
         synchronized(mPackages) {
             if (mSettings.mRenamedPackages.containsKey(pkgName)) {
@@ -7638,6 +8015,7 @@
         // First find the old package info and check signatures
         synchronized(mPackages) {
             oldPackage = mPackages.get(pkgName);
+            if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
             if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
                     != PackageManager.SIGNATURE_MATCH) {
                 Slog.w(TAG, "New package has a different signature: " + pkgName);
@@ -7663,6 +8041,8 @@
         boolean deletedPkg = true;
         boolean updatedSettings = false;
 
+        if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
+                + deletedPackage);
         long origUpdateTime;
         if (pkg.mExtras != null) {
             origUpdateTime = ((PackageSetting)pkg.mExtras).lastUpdateTime;
@@ -7700,6 +8080,7 @@
             // scanPackageLocked, unless those directories existed before we even tried to
             // install.
             if(updatedSettings) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, rolling pack: " + pkgName);
                 deletePackageLI(
                         pkgName, null, true,
                         PackageManager.DELETE_KEEP_DATA,
@@ -7708,6 +8089,7 @@
             // Since we failed to install the new package we need to restore the old
             // package that we deleted.
             if(deletedPkg) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
                 File restoreFile = new File(deletedPackage.mPath);
                 // Parse old package
                 boolean oldOnSd = isExternal(deletedPackage);
@@ -7737,6 +8119,8 @@
     private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
             String installerPackageName, PackageInstalledInfo res) {
+        if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+                + ", old=" + deletedPackage);
         PackageParser.Package newPackage = null;
         boolean updatedSettings = false;
         parseFlags |= PackageManager.INSTALL_REPLACE_EXISTING |
@@ -7859,7 +8243,7 @@
             return;
         }
 
-        Log.d(TAG, "New package installed in " + newPackage.mPath);
+        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath);
 
         synchronized (mPackages) {
             updatePermissionsLPw(newPackage.packageName, newPackage,
@@ -7889,6 +8273,7 @@
         // Result object to be returned
         res.returnCode = PackageManager.INSTALL_SUCCEEDED;
 
+        if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);
         // Retrieve PackageSettings and parse package
         int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                 | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
@@ -7950,14 +8335,18 @@
                     pkg.setPackageName(oldName);
                     pkgName = pkg.packageName;
                     replace = true;
+                    if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
+                            + oldName + " pkgName=" + pkgName);
                 } else if (mPackages.containsKey(pkgName)) {
                     // This package, under its official name, already exists
                     // on the device; we should replace it.
                     replace = true;
+                    if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
                 }
             }
             PackageSetting ps = mSettings.mPackages.get(pkgName);
             if (ps != null) {
+                if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
                 oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
                 if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                     systemApp = (ps.pkg.applicationInfo.flags &
@@ -8025,6 +8414,10 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
 
+    private static boolean isUpdatedSystemApp(PackageSetting ps) {
+        return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+    }
+
     private static boolean isUpdatedSystemApp(PackageParser.Package pkg) {
         return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
@@ -8096,7 +8489,7 @@
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     "deletePackage for user " + userId);
         }
-        if (!isUserAllowed(userId, UserManager.ALLOW_UNINSTALL_APPS)) {
+        if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
             try {
                 observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
             } catch (RemoteException re) {
@@ -8104,6 +8497,7 @@
             return;
         }
 
+        if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
@@ -8141,7 +8535,8 @@
         IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
-            if (dpm != null && dpm.packageHasActiveAdmins(packageName, userId)) {
+            if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId)
+                    || dpm.isDeviceOwner(packageName))) {
                 Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
                 return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
             }
@@ -8151,6 +8546,7 @@
         boolean removedForAllUsers = false;
         boolean systemUpdate = false;
         synchronized (mInstallLock) {
+            if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
             res = deletePackageLI(packageName,
                     (flags & PackageManager.DELETE_ALL_USERS) != 0
                             ? UserHandle.ALL : new UserHandle(userId),
@@ -8159,6 +8555,8 @@
             if (res && !systemUpdate && mPackages.get(packageName) == null) {
                 removedForAllUsers = true;
             }
+            if (DEBUG_REMOVE) Slog.d(TAG, "delete res: systemUpdate=" + systemUpdate
+                    + " removedForAllUsers=" + removedForAllUsers);
         }
 
         if (res) {
@@ -8234,6 +8632,7 @@
     private void removePackageDataLI(PackageSetting ps, PackageRemovedInfo outInfo,
             int flags, boolean writeSettings) {
         String packageName = ps.name;
+        if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
         removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
         // Retrieve object to delete permissions for shared user later on
         final PackageSetting deletedPs;
@@ -8274,6 +8673,19 @@
                 mSettings.writeLPr();
             }
         }
+        if (outInfo != null) {
+            // A user ID was deleted here. Go through all users and remove it
+            // from KeyStore.
+            final int appId = outInfo.removedAppId;
+            if (appId != -1) {
+                final KeyStore keyStore = KeyStore.getInstance();
+                if (keyStore != null) {
+                    for (final int userId : sUserManager.getUserIds()) {
+                        keyStore.clearUid(UserHandle.getUid(userId, appId));
+                    }
+                }
+            }
+        }
     }
 
     /*
@@ -8289,11 +8701,13 @@
         synchronized (mPackages) {
             disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);
         }
+        if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + newPs
+                + " disabledPs=" + disabledPs);
         if (disabledPs == null) {
             Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);
             return false;
-        } else {
-            Log.i(TAG, "Deleting system pkg from data partition");
+        } else if (DEBUG_REMOVE) {
+            Slog.d(TAG, "Deleting system pkg from data partition");
         }
         // Delete the updated package
         outInfo.isRemovedPackageSystemUpdate = true;
@@ -8317,6 +8731,7 @@
             NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString);
         }
         // Install the system package
+        if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
         PackageParser.Package newPkg = scanPackageLI(disabledPs.codePath,
                 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
                 SCAN_MONITOR | SCAN_NO_PATHS, 0, null);
@@ -8366,6 +8781,7 @@
             Slog.w(TAG, "Attempt to delete null packageName.");
             return false;
         }
+        if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
         PackageSetting ps;
         boolean dataOnly = false;
         int removeUser = -1;
@@ -8376,28 +8792,33 @@
                 Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                 return false;
             }
-            if (user != null
+            if ((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
                     && user.getIdentifier() != UserHandle.USER_ALL) {
                 // The caller is asking that the package only be deleted for a single
                 // user.  To do this, we just mark its uninstalled state and delete
-                // its data.
+                // its data.  If this is a system app, we only allow this to happen if
+                // they have set the special DELETE_SYSTEM_APP which requests different
+                // semantics than normal for uninstalling system apps.
+                if (DEBUG_REMOVE) Slog.d(TAG, "Only deleting for single user");
                 ps.setUserState(user.getIdentifier(),
                         COMPONENT_ENABLED_STATE_DEFAULT,
                         false, //installed
                         true,  //stopped
                         true,  //notLaunched
-                        null, null);
+                        null, null, null);
                 if (!isSystemApp(ps)) {
                     if (ps.isAnyInstalled(sUserManager.getUserIds())) {
                         // Other user still have this package installed, so all
                         // we need to do is clear this user's data and save that
                         // it is uninstalled.
+                        if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
                         removeUser = user.getIdentifier();
                         appId = ps.appId;
                         mSettings.writePackageRestrictionsLPr(removeUser);
                     } else {
                         // We need to set it back to 'installed' so the uninstall
                         // broadcasts will be sent correctly.
+                        if (DEBUG_REMOVE) Slog.d(TAG, "Not installed by other users, full delete");
                         ps.setInstalled(true, user.getIdentifier());
                     }
                 } else {
@@ -8405,6 +8826,7 @@
                     // other users still have this package installed, so all
                     // we need to do is clear this user's data and save that
                     // it is uninstalled.
+                    if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
                     removeUser = user.getIdentifier();
                     appId = ps.appId;
                     mSettings.writePackageRestrictionsLPr(removeUser);
@@ -8415,6 +8837,7 @@
         if (removeUser >= 0) {
             // From above, we determined that we are deleting this only
             // for a single user.  Continue the work here.
+            if (DEBUG_REMOVE) Slog.d(TAG, "Updating install state for user: " + removeUser);
             if (outInfo != null) {
                 outInfo.removedPackage = packageName;
                 outInfo.removedAppId = appId;
@@ -8427,17 +8850,18 @@
 
         if (dataOnly) {
             // Delete application data first
+            if (DEBUG_REMOVE) Slog.d(TAG, "Removing package data only");
             removePackageDataLI(ps, outInfo, flags, writeSettings);
             return true;
         }
         boolean ret = false;
         if (isSystemApp(ps)) {
-            Log.i(TAG, "Removing system package:" + ps.name);
+            if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
             // When an updated system application is deleted we delete the existing resources as well and
             // fall back to existing code in system partition
             ret = deleteSystemPackageLI(ps, flags, outInfo, writeSettings);
         } else {
-            Log.i(TAG, "Removing non-system package:" + ps.name);
+            if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
             // Kill application pre-emptively especially for apps on sd.
             killApplication(packageName, ps.appId);
             ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, outInfo,
@@ -8954,9 +9378,12 @@
 
     @Override
     public void setApplicationEnabledSetting(String appPackageName,
-            int newState, int flags, int userId) {
+            int newState, int flags, int userId, String callingPackage) {
         if (!sUserManager.exists(userId)) return;
-        setEnabledSetting(appPackageName, null, newState, flags, userId);
+        if (callingPackage == null) {
+            callingPackage = Integer.toString(Binder.getCallingUid());
+        }
+        setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage);
     }
 
     @Override
@@ -8964,11 +9391,11 @@
             int newState, int flags, int userId) {
         if (!sUserManager.exists(userId)) return;
         setEnabledSetting(componentName.getPackageName(),
-                componentName.getClassName(), newState, flags, userId);
+                componentName.getClassName(), newState, flags, userId, null);
     }
 
-    private void setEnabledSetting(
-            final String packageName, String className, int newState, final int flags, int userId) {
+    private void setEnabledSetting(final String packageName, String className, int newState,
+            final int flags, int userId, String callingPackage) {
         if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
               || newState == COMPONENT_ENABLED_STATE_ENABLED
               || newState == COMPONENT_ENABLED_STATE_DISABLED
@@ -9014,7 +9441,12 @@
                     // Nothing to do
                     return;
                 }
-                pkgSetting.setEnabled(newState, userId);
+                if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                    || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+                    // Don't care about who enables an app.
+                    callingPackage = null;
+                }
+                pkgSetting.setEnabled(newState, userId, callingPackage);
                 // pkgSetting.pkg.mSetEnabled = newState;
             } else {
                 // We're dealing with a component level state change
@@ -9408,7 +9840,15 @@
                     pw.print("  ");
                     pw.print(name);
                     pw.print(" -> ");
-                    pw.println(mSharedLibraries.get(name));
+                    SharedLibraryEntry ent = mSharedLibraries.get(name);
+                    if (ent.path != null) {
+                        pw.print("(jar) ");
+                        pw.print(ent.path);
+                    } else {
+                        pw.print("(apk) ");
+                        pw.print(ent.apk);
+                    }
+                    pw.println();
                 }
             }
 
@@ -10243,19 +10683,18 @@
                         || mSettings.mReadExternalStorageEnforced != enforced) {
                     mSettings.mReadExternalStorageEnforced = enforced;
                     mSettings.writeLPr();
-
-                    // kill any non-foreground processes so we restart them and
-                    // grant/revoke the GID.
-                    final IActivityManager am = ActivityManagerNative.getDefault();
-                    if (am != null) {
-                        final long token = Binder.clearCallingIdentity();
-                        try {
-                            am.killProcessesBelowForeground("setPermissionEnforcement");
-                        } catch (RemoteException e) {
-                        } finally {
-                            Binder.restoreCallingIdentity(token);
-                        }
-                    }
+                }
+            }
+            // kill any non-foreground processes so we restart them and
+            // grant/revoke the GID.
+            final IActivityManager am = ActivityManagerNative.getDefault();
+            if (am != null) {
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    am.killProcessesBelowForeground("setPermissionEnforcement");
+                } catch (RemoteException e) {
+                } finally {
+                    Binder.restoreCallingIdentity(token);
                 }
             }
         } else {
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index ae1b213..e64ec6d 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -189,14 +189,20 @@
         return DEFAULT_USER_STATE;
     }
 
-    void setEnabled(int state, int userId) {
-        modifyUserState(userId).enabled = state;
+    void setEnabled(int state, int userId, String callingPackage) {
+        PackageUserState st = modifyUserState(userId);
+        st.enabled = state;
+        st.lastDisableAppCaller = callingPackage;
     }
 
     int getEnabled(int userId) {
         return readUserState(userId).enabled;
     }
 
+    String getLastDisabledAppCaller(int userId) {
+        return readUserState(userId).lastDisableAppCaller;
+    }
+
     void setInstalled(boolean inst, int userId) {
         modifyUserState(userId).installed = inst;
     }
@@ -249,13 +255,14 @@
     }
 
     void setUserState(int userId, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, HashSet<String> enabledComponents,
+            boolean notLaunched, String lastDisableAppCaller, HashSet<String> enabledComponents,
             HashSet<String> disabledComponents) {
         PackageUserState state = modifyUserState(userId);
         state.enabled = enabled;
         state.installed = installed;
         state.stopped = stopped;
         state.notLaunched = notLaunched;
+        state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
     }
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/java/com/android/server/pm/PreferredIntentResolver.java
index 3f1e50c..7fe6a05 100644
--- a/services/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/java/com/android/server/pm/PreferredIntentResolver.java
@@ -27,8 +27,8 @@
         return new PreferredActivity[size];
     }
     @Override
-    protected String packageForFilter(PreferredActivity filter) {
-        return filter.mPref.mComponent.getPackageName();
+    protected boolean isPackageForFilter(String packageName, PreferredActivity filter) {
+        return packageName.equals(filter.mPref.mComponent.getPackageName());
     }
     @Override
     protected void dumpFilter(PrintWriter out, String prefix,
diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java
new file mode 100644
index 0000000..4bbdb5e
--- /dev/null
+++ b/services/java/com/android/server/pm/SELinuxMMAC.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.content.pm.Signature;
+import android.os.Environment;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+import java.util.HashMap;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Centralized access to SELinux MMAC (middleware MAC) implementation.
+ * {@hide}
+ */
+public final class SELinuxMMAC {
+
+    private static final String TAG = "SELinuxMMAC";
+
+    private static final boolean DEBUG_POLICY = false;
+    private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
+
+    // Signature seinfo values read from policy.
+    private static final HashMap<Signature, String> sSigSeinfo =
+        new HashMap<Signature, String>();
+
+    // Package name seinfo values read from policy.
+    private static final HashMap<String, String> sPackageSeinfo =
+        new HashMap<String, String>();
+
+    // Locations of potential install policy files.
+    private static final File[] INSTALL_POLICY_FILE = {
+        new File(Environment.getDataDirectory(), "system/mac_permissions.xml"),
+        new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"),
+        null};
+
+    private static void flushInstallPolicy() {
+        sSigSeinfo.clear();
+        sPackageSeinfo.clear();
+    }
+
+    /**
+     * Parses an MMAC install policy from a predefined list of locations.
+     * @param none
+     * @return boolean indicating whether an install policy was correctly parsed.
+     */
+    public static boolean readInstallPolicy() {
+
+        return readInstallPolicy(INSTALL_POLICY_FILE);
+    }
+
+    /**
+     * Parses an MMAC install policy given as an argument.
+     * @param File object representing the path of the policy.
+     * @return boolean indicating whether the install policy was correctly parsed.
+     */
+    public static boolean readInstallPolicy(File policyFile) {
+
+        return readInstallPolicy(new File[]{policyFile,null});
+    }
+
+    private static boolean readInstallPolicy(File[] policyFiles) {
+
+        FileReader policyFile = null;
+        int i = 0;
+        while (policyFile == null && policyFiles != null && policyFiles[i] != null) {
+            try {
+                policyFile = new FileReader(policyFiles[i]);
+                break;
+            } catch (FileNotFoundException e) {
+                Slog.d(TAG,"Couldn't find install policy " + policyFiles[i].getPath());
+            }
+            i++;
+        }
+
+        if (policyFile == null) {
+            Slog.d(TAG, "No policy file found. All seinfo values will be null.");
+            return false;
+        }
+
+        Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath());
+
+        flushInstallPolicy();
+
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(policyFile);
+
+            XmlUtils.beginDocument(parser, "policy");
+            while (true) {
+                XmlUtils.nextElement(parser);
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                String tagName = parser.getName();
+                if ("signer".equals(tagName)) {
+                    String cert = parser.getAttributeValue(null, "signature");
+                    if (cert == null) {
+                        Slog.w(TAG, "<signer> without signature at "
+                               + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    Signature signature;
+                    try {
+                        signature = new Signature(cert);
+                    } catch (IllegalArgumentException e) {
+                        Slog.w(TAG, "<signer> with bad signature at "
+                               + parser.getPositionDescription(), e);
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String seinfo = readSeinfoTag(parser);
+                    if (seinfo != null) {
+                        if (DEBUG_POLICY_INSTALL)
+                            Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo="
+                                   + seinfo);
+
+                        sSigSeinfo.put(signature, seinfo);
+                    }
+                } else if ("default".equals(tagName)) {
+                    String seinfo = readSeinfoTag(parser);
+                    if (seinfo != null) {
+                        if (DEBUG_POLICY_INSTALL)
+                            Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo);
+
+                        // The 'null' signature is the default seinfo value
+                        sSigSeinfo.put(null, seinfo);
+                    }
+                } else if ("package".equals(tagName)) {
+                    String pkgName = parser.getAttributeValue(null, "name");
+                    if (pkgName == null) {
+                        Slog.w(TAG, "<package> without name at "
+                               + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String seinfo = readSeinfoTag(parser);
+                    if (seinfo != null) {
+                        if (DEBUG_POLICY_INSTALL)
+                            Slog.i(TAG, "<package> tag: (" + pkgName +
+                                   ") assigned seinfo=" + seinfo);
+
+                        sPackageSeinfo.put(pkgName, seinfo);
+                    }
+                } else {
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+            }
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Got execption parsing ", e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Got execption parsing ", e);
+        }
+        try {
+            policyFile.close();
+        } catch (IOException e) {
+            //omit
+        }
+        return true;
+    }
+
+    private static String readSeinfoTag(XmlPullParser parser) throws
+            IOException, XmlPullParserException {
+
+        int type;
+        int outerDepth = parser.getDepth();
+        String seinfo = null;
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+               && (type != XmlPullParser.END_TAG
+                   || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG
+                || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if ("seinfo".equals(tagName)) {
+                String seinfoValue = parser.getAttributeValue(null, "value");
+                if (validateValue(seinfoValue)) {
+                    seinfo = seinfoValue;
+                } else {
+                    Slog.w(TAG, "<seinfo> without valid value at "
+                           + parser.getPositionDescription());
+                }
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+        return seinfo;
+    }
+
+    /**
+     * General validation routine for tag values.
+     * Returns a boolean indicating if the passed string
+     * contains only letters or underscores.
+     */
+    private static boolean validateValue(String name) {
+        if (name == null)
+            return false;
+
+        final int N = name.length();
+        if (N == 0)
+            return false;
+
+        for (int i = 0; i < N; i++) {
+            final char c = name.charAt(i);
+            if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c != '_')) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Labels a package based on an seinfo tag from install policy.
+     * The label is attached to the ApplicationInfo instance of the package.
+     * @param PackageParser.Package object representing the package
+     *         to labeled.
+     * @return String holding the value of the seinfo label that was assigned.
+     *         Value may be null which indicates no seinfo label was assigned.
+     */
+    public static void assignSeinfoValue(PackageParser.Package pkg) {
+
+        /*
+         * Non system installed apps should be treated the same. This
+         * means that any post-loaded apk will be assigned the default
+         * tag, if one exists in the policy, else null, without respect
+         * to the signing key.
+         */
+        if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||
+            ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
+
+            // We just want one of the signatures to match.
+            for (Signature s : pkg.mSignatures) {
+                if (s == null)
+                    continue;
+
+                if (sSigSeinfo.containsKey(s)) {
+                    String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s);
+                    if (DEBUG_POLICY_INSTALL)
+                        Slog.i(TAG, "package (" + pkg.packageName +
+                               ") labeled with seinfo=" + seinfo);
+
+                    return;
+                }
+            }
+
+            // Check for seinfo labeled by package.
+            if (sPackageSeinfo.containsKey(pkg.packageName)) {
+                String seinfo = pkg.applicationInfo.seinfo = sPackageSeinfo.get(pkg.packageName);
+                if (DEBUG_POLICY_INSTALL)
+                    Slog.i(TAG, "package (" + pkg.packageName +
+                           ") labeled with seinfo=" + seinfo);
+                return;
+            }
+        }
+
+        // If we have a default seinfo value then great, otherwise
+        // we set a null object and that is what we started with.
+        String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null);
+        if (DEBUG_POLICY_INSTALL)
+            Slog.i(TAG, "package (" + pkg.packageName +
+                   ") labeled with seinfo=" + (seinfo == null ? "null" : seinfo));
+    }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 13f514b..2e48074 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -32,7 +32,6 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 import com.android.internal.util.XmlUtils;
-import com.android.server.IntentResolver;
 import com.android.server.pm.PackageManagerService.DumpState;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -105,6 +104,7 @@
     private static final String ATTR_CODE = "code";
     private static final String ATTR_NOT_LAUNCHED = "nl";
     private static final String ATTR_ENABLED = "enabled";
+    private static final String ATTR_ENABLED_CALLER = "enabledCaller";
     private static final String ATTR_STOPPED = "stopped";
     private static final String ATTR_INSTALLED = "inst";
 
@@ -454,7 +454,7 @@
                                     installed,
                                     true, // stopped,
                                     true, // notLaunched
-                                    null, null);
+                                    null, null, null);
                             writePackageRestrictionsLPr(user.id);
                         }
                     }
@@ -851,7 +851,7 @@
                                 true,   // installed
                                 false,  // stopped
                                 false,  // notLaunched
-                                null, null);
+                                null, null, null);
                     }
                     return;
                 }
@@ -896,6 +896,8 @@
                     final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
                     final int enabled = enabledStr == null
                             ? COMPONENT_ENABLED_STATE_DEFAULT : Integer.parseInt(enabledStr);
+                    final String enabledCaller = parser.getAttributeValue(null,
+                            ATTR_ENABLED_CALLER);
                     final String installedStr = parser.getAttributeValue(null, ATTR_INSTALLED);
                     final boolean installed = installedStr == null
                             ? true : Boolean.parseBoolean(installedStr);
@@ -926,7 +928,7 @@
                     }
 
                     ps.setUserState(userId, enabled, installed, stopped, notLaunched,
-                            enabledComponents, disabledComponents);
+                            enabledCaller, enabledComponents, disabledComponents);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
                 } else {
@@ -1053,6 +1055,10 @@
                     if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
                         serializer.attribute(null, ATTR_ENABLED,
                                 Integer.toString(ustate.enabled));
+                        if (ustate.lastDisableAppCaller != null) {
+                            serializer.attribute(null, ATTR_ENABLED_CALLER,
+                                    ustate.lastDisableAppCaller);
+                        }
                     }
                     if (ustate.enabledComponents != null
                             && ustate.enabledComponents.size() > 0) {
@@ -1366,6 +1372,7 @@
                     // userId     - application-specific user id
                     // debugFlag  - 0 or 1 if the package is debuggable.
                     // dataPath   - path to package's data path
+                    // seinfo     - seinfo label for the app (assigned at install time)
                     //
                     // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                     //
@@ -1379,6 +1386,8 @@
                     sb.append((int)ai.uid);
                     sb.append(isDebug ? " 1 " : " 0 ");
                     sb.append(dataPath);
+                    sb.append(" ");
+                    sb.append(ai.seinfo);
                     sb.append("\n");
                     str.write(sb.toString().getBytes());
                 }
@@ -1594,9 +1603,6 @@
                     mReadMessages.append("No settings file found\n");
                     PackageManagerService.reportSettingsProblem(Log.INFO,
                             "No settings file; creating initial state");
-                    if (!onlyCore) {
-                        readDefaultPreferredAppsLPw(service, 0);
-                    }
                     mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
                     return false;
                 }
@@ -2240,14 +2246,14 @@
             final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
                 try {
-                    packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */);
+                    packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */, null);
                 } catch (NumberFormatException e) {
                     if (enabledStr.equalsIgnoreCase("true")) {
-                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0);
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0, null);
                     } else if (enabledStr.equalsIgnoreCase("false")) {
-                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0);
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
                     } else if (enabledStr.equalsIgnoreCase("default")) {
-                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0);
+                        packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
                     } else {
                         PackageManagerService.reportSettingsProblem(Log.WARN,
                                 "Error in package manager settings: package " + name
@@ -2256,7 +2262,7 @@
                     }
                 }
             } else {
-                packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0);
+                packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0, null);
             }
 
             final String installStatusStr = parser.getAttributeValue(null, "installStatus");
@@ -2657,6 +2663,167 @@
         ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
     };
 
+    void dumpPackageLPr(PrintWriter pw, String prefix, PackageSetting ps, SimpleDateFormat sdf,
+            Date date, List<UserInfo> users) {
+        pw.print(prefix); pw.print("Package [");
+            pw.print(ps.realName != null ? ps.realName : ps.name);
+            pw.print("] (");
+            pw.print(Integer.toHexString(System.identityHashCode(ps)));
+            pw.println("):");
+
+        if (ps.realName != null) {
+            pw.print(prefix); pw.print("  compat name=");
+            pw.println(ps.name);
+        }
+
+        pw.print(prefix); pw.print("  userId="); pw.print(ps.appId);
+                pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
+        if (ps.sharedUser != null) {
+            pw.print(prefix); pw.print("  sharedUser="); pw.println(ps.sharedUser);
+        }
+        pw.print(prefix); pw.print("  pkg="); pw.println(ps.pkg);
+        pw.print(prefix); pw.print("  codePath="); pw.println(ps.codePathString);
+        pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.resourcePathString);
+        pw.print(prefix); pw.print("  nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
+        pw.print(prefix); pw.print("  versionCode="); pw.print(ps.versionCode);
+        if (ps.pkg != null) {
+            pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion);
+        }
+        pw.println();
+        if (ps.pkg != null) {
+            pw.print(prefix); pw.print("  versionName="); pw.println(ps.pkg.mVersionName);
+            pw.print(prefix); pw.print("  applicationInfo=");
+                pw.println(ps.pkg.applicationInfo.toString());
+            pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
+                    FLAG_DUMP_SPEC); pw.println();
+            pw.print(prefix); pw.print("  dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+            if (ps.pkg.mOperationPending) {
+                pw.print(prefix); pw.println("  mOperationPending=true");
+            }
+            pw.print(prefix); pw.print("  supportsScreens=[");
+            boolean first = true;
+            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+                if (!first)
+                    pw.print(", ");
+                first = false;
+                pw.print("small");
+            }
+            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+                if (!first)
+                    pw.print(", ");
+                first = false;
+                pw.print("medium");
+            }
+            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+                if (!first)
+                    pw.print(", ");
+                first = false;
+                pw.print("large");
+            }
+            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+                if (!first)
+                    pw.print(", ");
+                first = false;
+                pw.print("xlarge");
+            }
+            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+                if (!first)
+                    pw.print(", ");
+                first = false;
+                pw.print("resizeable");
+            }
+            if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+                if (!first)
+                    pw.print(", ");
+                first = false;
+                pw.print("anyDensity");
+            }
+            pw.println("]");
+            if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) {
+                pw.print(prefix); pw.println("  libraries:");
+                for (int i=0; i<ps.pkg.libraryNames.size(); i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.libraryNames.get(i));
+                }
+            }
+            if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) {
+                pw.print(prefix); pw.println("  usesLibraries:");
+                for (int i=0; i<ps.pkg.usesLibraries.size(); i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraries.get(i));
+                }
+            }
+            if (ps.pkg.usesOptionalLibraries != null
+                    && ps.pkg.usesOptionalLibraries.size() > 0) {
+                pw.print(prefix); pw.println("  usesOptionalLibraries:");
+                for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) {
+                    pw.print(prefix); pw.print("    ");
+                        pw.println(ps.pkg.usesOptionalLibraries.get(i));
+                }
+            }
+            if (ps.pkg.usesLibraryFiles != null
+                    && ps.pkg.usesLibraryFiles.length > 0) {
+                pw.print(prefix); pw.println("  usesLibraryFiles:");
+                for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) {
+                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraryFiles[i]);
+                }
+            }
+        }
+        pw.print(prefix); pw.print("  timeStamp=");
+            date.setTime(ps.timeStamp);
+            pw.println(sdf.format(date));
+        pw.print(prefix); pw.print("  firstInstallTime=");
+            date.setTime(ps.firstInstallTime);
+            pw.println(sdf.format(date));
+        pw.print(prefix); pw.print("  lastUpdateTime=");
+            date.setTime(ps.lastUpdateTime);
+            pw.println(sdf.format(date));
+        if (ps.installerPackageName != null) {
+            pw.print(prefix); pw.print("  installerPackageName=");
+                    pw.println(ps.installerPackageName);
+        }
+        pw.print(prefix); pw.print("  signatures="); pw.println(ps.signatures);
+        pw.print(prefix); pw.print("  permissionsFixed="); pw.print(ps.permissionsFixed);
+                pw.print(" haveGids="); pw.print(ps.haveGids);
+                pw.print(" installStatus="); pw.println(ps.installStatus);
+        pw.print(prefix); pw.print("  pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
+                pw.println();
+        for (UserInfo user : users) {
+            pw.print(prefix); pw.print("  User "); pw.print(user.id); pw.print(": ");
+            pw.print(" installed=");
+            pw.print(ps.getInstalled(user.id));
+            pw.print(" stopped=");
+            pw.print(ps.getStopped(user.id));
+            pw.print(" notLaunched=");
+            pw.print(ps.getNotLaunched(user.id));
+            pw.print(" enabled=");
+            pw.println(ps.getEnabled(user.id));
+            String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+            if (lastDisabledAppCaller != null) {
+                pw.print(prefix); pw.print("    lastDisabledCaller: ");
+                        pw.println(lastDisabledAppCaller);
+            }
+            HashSet<String> cmp = ps.getDisabledComponents(user.id);
+            if (cmp != null && cmp.size() > 0) {
+                pw.print(prefix); pw.println("    disabledComponents:");
+                for (String s : cmp) {
+                    pw.print(prefix); pw.print("    "); pw.println(s);
+                }
+            }
+            cmp = ps.getEnabledComponents(user.id);
+            if (cmp != null && cmp.size() > 0) {
+                pw.print(prefix); pw.println("    enabledComponents:");
+                for (String s : cmp) {
+                    pw.print(prefix); pw.print("    "); pw.println(s);
+                }
+            }
+        }
+        if (ps.grantedPermissions.size() > 0) {
+            pw.print(prefix); pw.println("  grantedPermissions:");
+            for (String s : ps.grantedPermissions) {
+                pw.print(prefix); pw.print("    "); pw.println(s);
+            }
+        }
+    }
+
     void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
         final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         final Date date = new Date();
@@ -2678,123 +2845,7 @@
                 pw.println("Packages:");
                 printedSomething = true;
             }
-            pw.print("  Package [");
-                pw.print(ps.realName != null ? ps.realName : ps.name);
-                pw.print("] (");
-                pw.print(Integer.toHexString(System.identityHashCode(ps)));
-                pw.println("):");
-
-            if (ps.realName != null) {
-                pw.print("    compat name=");
-                pw.println(ps.name);
-            }
-
-            pw.print("    userId="); pw.print(ps.appId);
-            pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
-            pw.print("    sharedUser="); pw.println(ps.sharedUser);
-            pw.print("    pkg="); pw.println(ps.pkg);
-            pw.print("    codePath="); pw.println(ps.codePathString);
-            pw.print("    resourcePath="); pw.println(ps.resourcePathString);
-            pw.print("    nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
-            pw.print("    versionCode="); pw.println(ps.versionCode);
-            if (ps.pkg != null) {
-                pw.print("    applicationInfo="); pw.println(ps.pkg.applicationInfo.toString());
-                pw.print("    flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println();
-                pw.print("    versionName="); pw.println(ps.pkg.mVersionName);
-                pw.print("    dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
-                pw.print("    targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
-                if (ps.pkg.mOperationPending) {
-                    pw.println("    mOperationPending=true");
-                }
-                pw.print("    supportsScreens=[");
-                boolean first = true;
-                if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
-                    if (!first)
-                        pw.print(", ");
-                    first = false;
-                    pw.print("small");
-                }
-                if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
-                    if (!first)
-                        pw.print(", ");
-                    first = false;
-                    pw.print("medium");
-                }
-                if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
-                    if (!first)
-                        pw.print(", ");
-                    first = false;
-                    pw.print("large");
-                }
-                if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
-                    if (!first)
-                        pw.print(", ");
-                    first = false;
-                    pw.print("xlarge");
-                }
-                if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
-                    if (!first)
-                        pw.print(", ");
-                    first = false;
-                    pw.print("resizeable");
-                }
-                if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
-                    if (!first)
-                        pw.print(", ");
-                    first = false;
-                    pw.print("anyDensity");
-                }
-                pw.println("]");
-            }
-            pw.print("    timeStamp=");
-                date.setTime(ps.timeStamp);
-                pw.println(sdf.format(date));
-            pw.print("    firstInstallTime=");
-                date.setTime(ps.firstInstallTime);
-                pw.println(sdf.format(date));
-            pw.print("    lastUpdateTime=");
-                date.setTime(ps.lastUpdateTime);
-                pw.println(sdf.format(date));
-            if (ps.installerPackageName != null) {
-                pw.print("    installerPackageName="); pw.println(ps.installerPackageName);
-            }
-            pw.print("    signatures="); pw.println(ps.signatures);
-            pw.print("    permissionsFixed="); pw.print(ps.permissionsFixed);
-                    pw.print(" haveGids="); pw.print(ps.haveGids);
-                    pw.print(" installStatus="); pw.println(ps.installStatus);
-            pw.print("    pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
-                    pw.println();
-            for (UserInfo user : users) {
-                pw.print("    User "); pw.print(user.id); pw.print(": ");
-                pw.print(" installed=");
-                pw.print(ps.getInstalled(user.id));
-                pw.print(" stopped=");
-                pw.print(ps.getStopped(user.id));
-                pw.print(" notLaunched=");
-                pw.print(ps.getNotLaunched(user.id));
-                pw.print(" enabled=");
-                pw.println(ps.getEnabled(user.id));
-                HashSet<String> cmp = ps.getDisabledComponents(user.id);
-                if (cmp != null && cmp.size() > 0) {
-                    pw.println("      disabledComponents:");
-                    for (String s : cmp) {
-                        pw.print("      "); pw.println(s);
-                    }
-                }
-                cmp = ps.getEnabledComponents(user.id);
-                if (cmp != null && cmp.size() > 0) {
-                    pw.println("      enabledComponents:");
-                    for (String s : cmp) {
-                        pw.print("      "); pw.println(s);
-                    }
-                }
-            }
-            if (ps.grantedPermissions.size() > 0) {
-                pw.println("    grantedPermissions:");
-                for (String s : ps.grantedPermissions) {
-                    pw.print("      "); pw.println(s);
-                }
-            }
+            dumpPackageLPr(pw, "  ", ps, sdf, date, users);
         }
 
         printedSomething = false;
@@ -2830,27 +2881,7 @@
                     pw.println("Hidden system packages:");
                     printedSomething = true;
                 }
-                pw.print("  Package [");
-                pw.print(ps.realName != null ? ps.realName : ps.name);
-                pw.print("] (");
-                pw.print(Integer.toHexString(System.identityHashCode(ps)));
-                pw.println("):");
-                if (ps.realName != null) {
-                    pw.print("    compat name=");
-                    pw.println(ps.name);
-                }
-                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
-                    pw.print("    applicationInfo=");
-                    pw.println(ps.pkg.applicationInfo.toString());
-                }
-                pw.print("    userId=");
-                pw.println(ps.appId);
-                pw.print("    sharedUser=");
-                pw.println(ps.sharedUser);
-                pw.print("    codePath=");
-                pw.println(ps.codePathString);
-                pw.print("    resourcePath=");
-                pw.println(ps.resourcePathString);
+                dumpPackageLPr(pw, "  ", ps, sdf, date, users);
             }
         }
     }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 1414cbd..aa1b2ff 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -25,7 +25,9 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.RestrictionEntry;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -83,11 +85,17 @@
     private static final String TAG_USERS = "users";
     private static final String TAG_USER = "user";
     private static final String TAG_RESTRICTIONS = "restrictions";
+    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_MULTIPLE = "m";
 
     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";
 
+    private static final String RESTRICTIONS_FILE_PREFIX = "res_";
+
     private static final int MIN_USER_ID = 10;
 
     private static final int USER_VERSION = 2;
@@ -217,6 +225,13 @@
         }
     }
 
+    @Override
+    public boolean isRestricted() {
+        synchronized (mPackagesLock) {
+            return getUserInfoLocked(UserHandle.getCallingUserId()).isRestricted();
+        }
+    }
+
     /*
      * Should be locked on mUsers before calling this.
      */
@@ -549,7 +564,6 @@
         mNextSerialNumber = MIN_USER_ID;
 
         Bundle restrictions = new Bundle();
-        initRestrictionsToDefaults(restrictions);
         mUserRestrictions.append(UserHandle.USER_OWNER, restrictions);
 
         updateUserIdsLocked();
@@ -599,11 +613,15 @@
             Bundle restrictions = mUserRestrictions.get(userInfo.id);
             if (restrictions != null) {
                 serializer.startTag(null, TAG_RESTRICTIONS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_WIFI);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_INSTALL_APPS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
-                writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_LOCATION_ACCESS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_WIFI);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_INSTALL_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNINSTALL_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_SHARE_LOCATION);
+                writeBoolean(serializer, restrictions,
+                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
                 serializer.endTag(null, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
@@ -667,7 +685,6 @@
         long lastLoggedInTime = 0L;
         boolean partial = false;
         Bundle restrictions = new Bundle();
-        initRestrictionsToDefaults(restrictions);
 
         FileInputStream fis = null;
         try {
@@ -716,11 +733,15 @@
                             name = parser.getText();
                         }
                     } else if (TAG_RESTRICTIONS.equals(tag)) {
-                        readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_WIFI);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_INSTALL_APPS);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
-                        readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_LOCATION_ACCESS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_WIFI);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_MODIFY_ACCOUNTS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_INSTALL_APPS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_UNINSTALL_APPS);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_SHARE_LOCATION);
+                        readBoolean(parser, restrictions,
+                                UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_BLUETOOTH);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_USB_FILE_TRANSFER);
                     }
                 }
             }
@@ -749,7 +770,9 @@
     private void readBoolean(XmlPullParser parser, Bundle restrictions,
             String restrictionKey) {
         String value = parser.getAttributeValue(null, restrictionKey);
-        restrictions.putBoolean(restrictionKey, value == null ? true : Boolean.parseBoolean(value));
+        if (value != null) {
+            restrictions.putBoolean(restrictionKey, Boolean.parseBoolean(value));
+        }
     }
 
     private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey)
@@ -760,14 +783,6 @@
         }
     }
 
-    private void initRestrictionsToDefaults(Bundle restrictions) {
-        restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
-        restrictions.putBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS, true);
-        restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, true);
-        restrictions.putBoolean(UserManager.ALLOW_UNINSTALL_APPS, true);
-        restrictions.putBoolean(UserManager.ALLOW_CONFIG_LOCATION_ACCESS, true);
-    }
-
     private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
         String valueString = parser.getAttributeValue(null, attr);
         if (valueString == null) return defaultValue;
@@ -814,7 +829,6 @@
                     writeUserLocked(userInfo);
                     updateUserIdsLocked();
                     Bundle restrictions = new Bundle();
-                    initRestrictionsToDefaults(restrictions);
                     mUserRestrictions.append(userId, restrictions);
                 }
             }
@@ -947,6 +961,151 @@
     }
 
     @Override
+    public List<RestrictionEntry> getApplicationRestrictions(String packageName, int userId) {
+        if (UserHandle.getCallingUserId() != userId
+                || Binder.getCallingUid() != getUidForPackage(packageName)) {
+            checkManageUsersPermission("Only system can get restrictions for other users/apps");
+        }
+        synchronized (mPackagesLock) {
+            // Read the restrictions from XML
+            return readApplicationRestrictionsLocked(packageName, userId);
+        }
+    }
+
+    @Override
+    public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+            int userId) {
+        if (UserHandle.getCallingUserId() != userId
+                || Binder.getCallingUid() != getUidForPackage(packageName)) {
+            checkManageUsersPermission("Only system can set restrictions for other users/apps");
+        }
+        synchronized (mPackagesLock) {
+            // Write the restrictions to XML
+            writeApplicationRestrictionsLocked(packageName, entries, userId);
+        }
+    }
+
+    private int getUidForPackage(String packageName) {
+        try {
+            return mContext.getPackageManager().getApplicationInfo(packageName,
+                    PackageManager.GET_UNINSTALLED_PACKAGES).uid;
+        } catch (NameNotFoundException nnfe) {
+            return -1;
+        }
+    }
+
+    private List<RestrictionEntry> readApplicationRestrictionsLocked(String packageName,
+            int userId) {
+        final ArrayList<RestrictionEntry> entries = new ArrayList<RestrictionEntry>();
+        final ArrayList<String> values = new ArrayList<String>();
+
+        FileInputStream fis = null;
+        try {
+            AtomicFile restrictionsFile =
+                    new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
+                            RESTRICTIONS_FILE_PREFIX + packageName + ".xml"));
+            fis = restrictionsFile.openRead();
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(fis, null);
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                Slog.e(LOG_TAG, "Unable to read restrictions file "
+                        + restrictionsFile.getBaseFile());
+                return entries;
+            }
+
+            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 multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
+                    if (multiple != null) {
+                        int count = Integer.parseInt(multiple);
+                        while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                            if (type == XmlPullParser.START_TAG
+                                    && parser.getName().equals(TAG_VALUE)) {
+                                values.add(parser.nextText().trim());
+                                count--;
+                            }
+                        }
+                        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);
+                    } else {
+                        String value = parser.nextText().trim();
+                        Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + value);
+                        RestrictionEntry entry = new RestrictionEntry(key, value);
+                        entries.add(entry);
+                    }
+                }
+            }
+
+        } catch (IOException ioe) {
+        } catch (XmlPullParserException pe) {
+        } finally {
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        return entries;
+    }
+
+    private void writeApplicationRestrictionsLocked(String packageName,
+            List<RestrictionEntry> entries, int userId) {
+        FileOutputStream fos = null;
+        AtomicFile restrictionsFile = new AtomicFile(
+                new File(Environment.getUserSystemDirectory(userId),
+                        RESTRICTIONS_FILE_PREFIX + packageName + ".xml"));
+        try {
+            fos = restrictionsFile.startWrite();
+            final BufferedOutputStream bos = new BufferedOutputStream(fos);
+
+            // XmlSerializer serializer = XmlUtils.serializerInstance();
+            final XmlSerializer serializer = new FastXmlSerializer();
+            serializer.setOutput(bos, "utf-8");
+            serializer.startDocument(null, true);
+            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+            serializer.startTag(null, TAG_RESTRICTIONS);
+
+            for (RestrictionEntry entry : entries) {
+                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 : "");
+                } else {
+                    String[] values = entry.getAllSelectedStrings();
+                    serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
+                    for (String value : values) {
+                        serializer.startTag(null, TAG_VALUE);
+                        serializer.text(value != null ? value : "");
+                        serializer.endTag(null, TAG_VALUE);
+                    }
+                }
+                serializer.endTag(null, TAG_ENTRY);
+            }
+
+            serializer.endTag(null, TAG_RESTRICTIONS);
+
+            serializer.endDocument();
+            restrictionsFile.finishWrite(fos);
+        } catch (Exception e) {
+            restrictionsFile.failWrite(fos);
+            Slog.e(LOG_TAG, "Error writing application restrictions list");
+        }
+    }
+
+    @Override
     public int getUserSerialNumber(int userHandle) {
         synchronized (mPackagesLock) {
             if (!exists(userHandle)) return -1;
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 457e92d..4a74149 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -82,7 +82,7 @@
     private int mDisplayHeight;     // real height, not rotated
     private SurfaceSession mSurfaceSession;
     private SurfaceControl mSurfaceControl;
-    private final Surface mSurface = new Surface();
+    private Surface mSurface;
     private NaturalSurfaceLayout mSurfaceLayout;
     private EGLDisplay mEglDisplay;
     private EGLConfig mEglConfig;
@@ -519,6 +519,7 @@
 
             mSurfaceControl.setLayerStack(mDisplayLayerStack);
             mSurfaceControl.setSize(mDisplayWidth, mDisplayHeight);
+            mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
             
             mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index b065310..c94f7c1 100644
--- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -102,6 +102,7 @@
                         Slog.i(TAG, "Found new update, installing...");
                         install(altContent, altVersion);
                         Slog.i(TAG, "Installation successful");
+                        postInstall(context, intent);
                     }
                 } catch (Exception e) {
                     Slog.e(TAG, "Could not update content!", e);
@@ -225,8 +226,6 @@
         FileOutputStream out = null;
         File tmp = null;
         try {
-            // create the temporary file
-            tmp = File.createTempFile("journal", "", dir);
             // create the parents for the destination file
             File parent = file.getParentFile();
             parent.mkdirs();
@@ -234,6 +233,8 @@
             if (!parent.exists()) {
                 throw new IOException("Failed to create directory " + parent.getCanonicalPath());
             }
+            // create the temporary file
+            tmp = File.createTempFile("journal", "", dir);
             // mark tmp -rw-r--r--
             tmp.setReadable(true, false);
             // write to it
@@ -257,4 +258,7 @@
         writeUpdate(updateDir, updateContent, content);
         writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
     }
+
+    protected void postInstall(Context context, Intent intent) {
+    }
 }
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
new file mode 100644
index 0000000..9185903
--- /dev/null
+++ b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
@@ -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.
+ */
+
+package com.android.server.updates;
+
+import com.android.server.firewall.IntentFirewall;
+
+public class IntentFirewallInstallReceiver extends ConfigUpdateInstallReceiver {
+
+    public IntentFirewallInstallReceiver() {
+        super(IntentFirewall.getRulesFile().getParent(), IntentFirewall.getRulesFile().getName(),
+                "metadata/", "version");
+    }
+}
diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
new file mode 100644
index 0000000..748849e
--- /dev/null
+++ b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -0,0 +1,45 @@
+/*
+ * 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.server.updates;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.SELinux;
+import android.provider.Settings;
+import android.util.Base64;
+import android.util.Slog;
+
+import java.io.IOException;
+
+public class SELinuxPolicyInstallReceiver extends ConfigUpdateInstallReceiver {
+
+    public SELinuxPolicyInstallReceiver() {
+        super("/data/security/", "sepolicy", "metadata/", "version");
+    }
+
+    @Override
+    protected void install(byte[] encodedContent, int version) throws IOException {
+        super.install(Base64.decode(encodedContent, Base64.DEFAULT), version);
+    }
+
+    @Override
+    protected void postInstall(Context context, Intent intent) {
+           boolean mode = Settings.Global.getInt(context.getContentResolver(),
+                                                Settings.Global.SELINUX_STATUS, 0) == 1;
+           SELinux.setSELinuxEnforce(mode);
+    }
+}
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java
index f9aaa17..9b5b312 100644
--- a/services/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbSettingsManager.java
@@ -34,6 +34,7 @@
 import android.hardware.usb.UsbManager;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.Process;
 import android.os.UserHandle;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -853,21 +854,29 @@
 
     public boolean hasPermission(UsbDevice device) {
         synchronized (mLock) {
+            int uid = Binder.getCallingUid();
+            if (uid == Process.SYSTEM_UID) {
+                return true;
+            }
             SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
             if (uidList == null) {
                 return false;
             }
-            return uidList.get(Binder.getCallingUid());
+            return uidList.get(uid);
         }
     }
 
     public boolean hasPermission(UsbAccessory accessory) {
         synchronized (mLock) {
+            int uid = Binder.getCallingUid();
+            if (uid == Process.SYSTEM_UID) {
+                return true;
+            }
             SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
             if (uidList == null) {
                 return false;
             }
-            return uidList.get(Binder.getCallingUid());
+            return uidList.get(uid);
         }
     }
 
diff --git a/services/java/com/android/server/wifi/README.txt b/services/java/com/android/server/wifi/README.txt
new file mode 100644
index 0000000..39e14751
--- /dev/null
+++ b/services/java/com/android/server/wifi/README.txt
@@ -0,0 +1,19 @@
+WifiService: Implements the IWifiManager 3rd party API. The API and the device state information (screen on/off, battery state, sleep policy) go as input into the WifiController which tracks high level states as to whether STA or AP mode is operational and controls the WifiStateMachine to handle bringup and shut down.
+
+WifiController: Acts as a controller to the WifiStateMachine based on various inputs (API and device state). Runs on the same thread created in WifiService.
+
+WifiSettingsStore: Tracks the various settings (wifi toggle, airplane toggle, tethering toggle, scan mode toggle) and provides API to figure if wifi should be turned on or off.
+
+WifiTrafficPoller: Polls traffic on wifi and notifies apps listening on it.
+
+WifiNotificationController: Controls whether the open network notification is displayed or not based on the scan results.
+
+WifiStateMachine: Tracks the various states on STA and AP connectivity and handles bring up and shut down.
+
+
+Feature description:
+
+Scan-only mode with Wi-Fi turned off:
+ - Setup wizard opts user into allowing scanning for improved location. We show no further dialogs in setup wizard since the user has just opted into the feature. This is the reason WifiService listens to DEVICE_PROVISIONED setting.
+ - Once the user has his device provisioned, turning off Wi-Fi from settings or from a third party app will show up a dialog reminding the user that scan mode will be on even though Wi-Fi is being turned off. The user has the choice to turn this notification off.
+ - In the scan mode, the device continues to allow scanning from any app with Wi-Fi turned off. This is done by disabling all networks and allowing only scans to be passed.
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java
new file mode 100644
index 0000000..6e6b8cc
--- /dev/null
+++ b/services/java/com/android/server/wifi/WifiController.java
@@ -0,0 +1,626 @@
+/*
+ * 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.server.wifi;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import static android.net.wifi.WifiManager.WIFI_MODE_FULL;
+import static android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF;
+import static android.net.wifi.WifiManager.WIFI_MODE_SCAN_ONLY;
+import android.net.wifi.WifiStateMachine;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.WorkSource;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.server.wifi.WifiService.LockList;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+class WifiController extends StateMachine {
+    private static final String TAG = "WifiController";
+    private static final boolean DBG = false;
+    private Context mContext;
+    private boolean mScreenOff;
+    private boolean mDeviceIdle;
+    private int mPluggedType;
+    private int mStayAwakeConditions;
+    private long mIdleMillis;
+    private int mSleepPolicy;
+
+    private AlarmManager mAlarmManager;
+    private PendingIntent mIdleIntent;
+    private static final int IDLE_REQUEST = 0;
+
+    /**
+     * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
+     * Settings.Global value is not present. This timeout value is chosen as
+     * the approximate point at which the battery drain caused by Wi-Fi
+     * being enabled but not active exceeds the battery drain caused by
+     * re-establishing a connection to the mobile data network.
+     */
+    private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
+
+    NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
+
+    private static final String ACTION_DEVICE_IDLE =
+            "com.android.server.WifiManager.action.DEVICE_IDLE";
+
+    /* References to values tracked in WifiService */
+    final WifiStateMachine mWifiStateMachine;
+    final WifiSettingsStore mSettingsStore;
+    final LockList mLocks;
+
+    /**
+     * Temporary for computing UIDS that are responsible for starting WIFI.
+     * Protected by mWifiStateTracker lock.
+     */
+    private final WorkSource mTmpWorkSource = new WorkSource();
+
+    private static final int BASE = Protocol.BASE_WIFI_CONTROLLER;
+
+    static final int CMD_EMERGENCY_MODE_CHANGED     = BASE + 1;
+    static final int CMD_SCREEN_ON                  = BASE + 2;
+    static final int CMD_SCREEN_OFF                 = BASE + 3;
+    static final int CMD_BATTERY_CHANGED            = BASE + 4;
+    static final int CMD_DEVICE_IDLE                = BASE + 5;
+    static final int CMD_LOCKS_CHANGED              = BASE + 6;
+    static final int CMD_SCAN_ALWAYS_MODE_CHANGED   = BASE + 7;
+    static final int CMD_WIFI_TOGGLED               = BASE + 8;
+    static final int CMD_AIRPLANE_TOGGLED           = BASE + 9;
+    static final int CMD_SET_AP                     = BASE + 10;
+
+    private DefaultState mDefaultState = new DefaultState();
+    private StaEnabledState mStaEnabledState = new StaEnabledState();
+    private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState();
+    private StaDisabledWithScanState mStaDisabledWithScanState = new StaDisabledWithScanState();
+    private ApEnabledState mApEnabledState = new ApEnabledState();
+    private DeviceActiveState mDeviceActiveState = new DeviceActiveState();
+    private DeviceInactiveState mDeviceInactiveState = new DeviceInactiveState();
+    private ScanOnlyLockHeldState mScanOnlyLockHeldState = new ScanOnlyLockHeldState();
+    private FullLockHeldState mFullLockHeldState = new FullLockHeldState();
+    private FullHighPerfLockHeldState mFullHighPerfLockHeldState = new FullHighPerfLockHeldState();
+    private NoLockHeldState mNoLockHeldState = new NoLockHeldState();
+    private EcmState mEcmState = new EcmState();
+
+    WifiController(Context context, WifiService service, Looper looper) {
+        super(TAG, looper);
+        mContext = context;
+        mWifiStateMachine = service.mWifiStateMachine;
+        mSettingsStore = service.mSettingsStore;
+        mLocks = service.mLocks;
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
+        mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
+
+        addState(mDefaultState);
+            addState(mApStaDisabledState, mDefaultState);
+            addState(mStaEnabledState, mDefaultState);
+                addState(mDeviceActiveState, mStaEnabledState);
+                addState(mDeviceInactiveState, mStaEnabledState);
+                    addState(mScanOnlyLockHeldState, mDeviceInactiveState);
+                    addState(mFullLockHeldState, mDeviceInactiveState);
+                    addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
+                    addState(mNoLockHeldState, mDeviceInactiveState);
+            addState(mStaDisabledWithScanState, mDefaultState);
+            addState(mApEnabledState, mDefaultState);
+            addState(mEcmState, mDefaultState);
+        setInitialState(mApStaDisabledState);
+        setLogRecSize(25);
+        setLogOnlyTransitions(true);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_DEVICE_IDLE);
+        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mContext.registerReceiver(
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        String action = intent.getAction();
+                        if (action.equals(ACTION_DEVICE_IDLE)) {
+                            sendMessage(CMD_DEVICE_IDLE);
+                        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
+                                    WifiManager.EXTRA_NETWORK_INFO);
+                        }
+                    }
+                },
+                new IntentFilter(filter));
+
+        initializeAndRegisterForSettingsChange(looper);
+    }
+
+    private void initializeAndRegisterForSettingsChange(Looper looper) {
+        Handler handler = new Handler(looper);
+        readStayAwakeConditions();
+        registerForStayAwakeModeChange(handler);
+        readWifiIdleTime();
+        registerForWifiIdleTimeChange(handler);
+        readWifiSleepPolicy();
+        registerForWifiSleepPolicyChange(handler);
+    }
+
+    private void readStayAwakeConditions() {
+        mStayAwakeConditions = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+    }
+
+    private void readWifiIdleTime() {
+        mIdleMillis = Settings.Global.getLong(mContext.getContentResolver(),
+                Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
+    }
+
+    private void readWifiSleepPolicy() {
+        mSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SLEEP_POLICY,
+                Settings.Global.WIFI_SLEEP_POLICY_NEVER);
+    }
+
+    /**
+     * Observes settings changes to scan always mode.
+     */
+    private void registerForStayAwakeModeChange(Handler handler) {
+        ContentObserver contentObserver = new ContentObserver(handler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                readStayAwakeConditions();
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.STAY_ON_WHILE_PLUGGED_IN),
+                false, contentObserver);
+    }
+
+    /**
+     * Observes settings changes to scan always mode.
+     */
+    private void registerForWifiIdleTimeChange(Handler handler) {
+        ContentObserver contentObserver = new ContentObserver(handler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                readWifiIdleTime();
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.WIFI_IDLE_MS),
+                false, contentObserver);
+    }
+
+    /**
+     * Observes changes to wifi sleep policy
+     */
+    private void registerForWifiSleepPolicyChange(Handler handler) {
+        ContentObserver contentObserver = new ContentObserver(handler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                readWifiSleepPolicy();
+            }
+        };
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY),
+                false, contentObserver);
+    }
+
+    /**
+     * Determines whether the Wi-Fi chipset should stay awake or be put to
+     * sleep. Looks at the setting for the sleep policy and the current
+     * conditions.
+     *
+     * @see #shouldDeviceStayAwake(int)
+     */
+    private boolean shouldWifiStayAwake(int pluggedType) {
+        if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
+            // Never sleep
+            return true;
+        } else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
+                (pluggedType != 0)) {
+            // Never sleep while plugged, and we're plugged
+            return true;
+        } else {
+            // Default
+            return shouldDeviceStayAwake(pluggedType);
+        }
+    }
+
+    /**
+     * Determine whether the bit value corresponding to {@code pluggedType} is set in
+     * the bit string mStayAwakeConditions. This determines whether the device should
+     * stay awake based on the current plugged type.
+     *
+     * @param pluggedType the type of plug (USB, AC, or none) for which the check is
+     * being made
+     * @return {@code true} if {@code pluggedType} indicates that the device is
+     * supposed to stay awake, {@code false} otherwise.
+     */
+    private boolean shouldDeviceStayAwake(int pluggedType) {
+        return (mStayAwakeConditions & pluggedType) != 0;
+    }
+
+    private void updateBatteryWorkSource() {
+        mTmpWorkSource.clear();
+        if (mDeviceIdle) {
+            mLocks.updateWorkSource(mTmpWorkSource);
+        }
+        mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
+    }
+
+    class DefaultState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_SCREEN_ON:
+                    mAlarmManager.cancel(mIdleIntent);
+                    mScreenOff = false;
+                    mDeviceIdle = false;
+                    updateBatteryWorkSource();
+                    break;
+                case CMD_SCREEN_OFF:
+                    mScreenOff = true;
+                    /*
+                    * Set a timer to put Wi-Fi to sleep, but only if the screen is off
+                    * AND the "stay on while plugged in" setting doesn't match the
+                    * current power conditions (i.e, not plugged in, plugged in to USB,
+                    * or plugged in to AC).
+                    */
+                    if (!shouldWifiStayAwake(mPluggedType)) {
+                        //Delayed shutdown if wifi is connected
+                        if (mNetworkInfo.getDetailedState() ==
+                                NetworkInfo.DetailedState.CONNECTED) {
+                            if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms");
+                            mAlarmManager.set(AlarmManager.RTC_WAKEUP,
+                                    System.currentTimeMillis() + mIdleMillis, mIdleIntent);
+                        } else {
+                            sendMessage(CMD_DEVICE_IDLE);
+                        }
+                    }
+                    break;
+                case CMD_DEVICE_IDLE:
+                    mDeviceIdle = true;
+                    updateBatteryWorkSource();
+                    break;
+                case CMD_BATTERY_CHANGED:
+                    /*
+                    * Set a timer to put Wi-Fi to sleep, but only if the screen is off
+                    * AND we are transitioning from a state in which the device was supposed
+                    * to stay awake to a state in which it is not supposed to stay awake.
+                    * If "stay awake" state is not changing, we do nothing, to avoid resetting
+                    * the already-set timer.
+                    */
+                    int pluggedType = msg.arg1;
+                    if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType);
+                    if (mScreenOff && shouldWifiStayAwake(mPluggedType) &&
+                            !shouldWifiStayAwake(pluggedType)) {
+                        long triggerTime = System.currentTimeMillis() + mIdleMillis;
+                        if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms");
+                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
+                    }
+
+                    mPluggedType = pluggedType;
+                    break;
+                case CMD_SET_AP:
+                case CMD_SCAN_ALWAYS_MODE_CHANGED:
+                case CMD_LOCKS_CHANGED:
+                case CMD_WIFI_TOGGLED:
+                case CMD_AIRPLANE_TOGGLED:
+                case CMD_EMERGENCY_MODE_CHANGED:
+                    break;
+                default:
+                    throw new RuntimeException("WifiController.handleMessage " + msg.what);
+            }
+            return HANDLED;
+        }
+
+    }
+
+    class ApStaDisabledState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setSupplicantRunning(false);
+        }
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_WIFI_TOGGLED:
+                case CMD_AIRPLANE_TOGGLED:
+                    if (mSettingsStore.isWifiToggleEnabled()) {
+                        if (mDeviceIdle == false) {
+                            transitionTo(mDeviceActiveState);
+                        } else {
+                            checkLocksAndTransitionWhenDeviceIdle();
+                        }
+                    }
+                    break;
+                case CMD_SCAN_ALWAYS_MODE_CHANGED:
+                    if (mSettingsStore.isScanAlwaysAvailable()) {
+                        transitionTo(mStaDisabledWithScanState);
+                    }
+                    break;
+                case CMD_SET_AP:
+                    if (msg.arg1 == 1) {
+                        mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
+                                true);
+                        transitionTo(mApEnabledState);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+
+    }
+
+    class StaEnabledState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setSupplicantRunning(true);
+        }
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_WIFI_TOGGLED:
+                    if (! mSettingsStore.isWifiToggleEnabled()) {
+                        if (mSettingsStore.isScanAlwaysAvailable()) {
+                            transitionTo(mStaDisabledWithScanState);
+                        } else {
+                            transitionTo(mApStaDisabledState);
+                        }
+                    }
+                    break;
+                case CMD_AIRPLANE_TOGGLED:
+                    /* When wi-fi is turned off due to airplane,
+                    * disable entirely (including scan)
+                    */
+                    if (! mSettingsStore.isWifiToggleEnabled()) {
+                        transitionTo(mApStaDisabledState);
+                    }
+                    break;
+                case CMD_EMERGENCY_MODE_CHANGED:
+                    if (msg.arg1 == 1) {
+                        transitionTo(mEcmState);
+                        break;
+                    }
+                default:
+                    return NOT_HANDLED;
+
+            }
+            return HANDLED;
+        }
+    }
+
+    class StaDisabledWithScanState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setSupplicantRunning(true);
+            mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_WITH_WIFI_OFF_MODE);
+            mWifiStateMachine.setDriverStart(true);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_WIFI_TOGGLED:
+                    if (mSettingsStore.isWifiToggleEnabled()) {
+                        if (mDeviceIdle == false) {
+                            transitionTo(mDeviceActiveState);
+                        } else {
+                            checkLocksAndTransitionWhenDeviceIdle();
+                        }
+                    }
+                    break;
+                case CMD_AIRPLANE_TOGGLED:
+                    if (mSettingsStore.isAirplaneModeOn() &&
+                            ! mSettingsStore.isWifiToggleEnabled()) {
+                        transitionTo(mApStaDisabledState);
+                    }
+                case CMD_SCAN_ALWAYS_MODE_CHANGED:
+                    if (! mSettingsStore.isScanAlwaysAvailable()) {
+                        transitionTo(mApStaDisabledState);
+                    }
+                    break;
+                case CMD_SET_AP:
+                    // Before starting tethering, turn off supplicant for scan mode
+                    if (msg.arg1 == 1) {
+                        deferMessage(msg);
+                        transitionTo(mApStaDisabledState);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    class ApEnabledState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_AIRPLANE_TOGGLED:
+                    if (mSettingsStore.isAirplaneModeOn()) {
+                        mWifiStateMachine.setHostApRunning(null, false);
+                        transitionTo(mApStaDisabledState);
+                    }
+                    break;
+                case CMD_SET_AP:
+                    if (msg.arg1 == 0) {
+                        mWifiStateMachine.setHostApRunning(null, false);
+                        transitionTo(mApStaDisabledState);
+                    }
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    class EcmState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setSupplicantRunning(false);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            if (msg.what == CMD_EMERGENCY_MODE_CHANGED && msg.arg1 == 0) {
+                if (mSettingsStore.isWifiToggleEnabled()) {
+                    if (mDeviceIdle == false) {
+                        transitionTo(mDeviceActiveState);
+                    } else {
+                        checkLocksAndTransitionWhenDeviceIdle();
+                    }
+                } else if (mSettingsStore.isScanAlwaysAvailable()) {
+                    transitionTo(mStaDisabledWithScanState);
+                } else {
+                    transitionTo(mApStaDisabledState);
+                }
+                return HANDLED;
+            } else {
+                return NOT_HANDLED;
+            }
+        }
+    }
+
+    /* Parent: StaEnabledState */
+    class DeviceActiveState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+            mWifiStateMachine.setDriverStart(true);
+            mWifiStateMachine.setHighPerfModeEnabled(false);
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            if (msg.what == CMD_DEVICE_IDLE) {
+                checkLocksAndTransitionWhenDeviceIdle();
+                // We let default state handle the rest of work
+            }
+            return NOT_HANDLED;
+        }
+    }
+
+    /* Parent: StaEnabledState */
+    class DeviceInactiveState extends State {
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_LOCKS_CHANGED:
+                    checkLocksAndTransitionWhenDeviceIdle();
+                    updateBatteryWorkSource();
+                    return HANDLED;
+                case CMD_SCREEN_ON:
+                    transitionTo(mDeviceActiveState);
+                    // More work in default state
+                    return NOT_HANDLED;
+                default:
+                    return NOT_HANDLED;
+            }
+        }
+    }
+
+    /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a scan only lock. */
+    class ScanOnlyLockHeldState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setOperationalMode(WifiStateMachine.SCAN_ONLY_MODE);
+            mWifiStateMachine.setDriverStart(true);
+        }
+    }
+
+    /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a full lock. */
+    class FullLockHeldState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+            mWifiStateMachine.setDriverStart(true);
+            mWifiStateMachine.setHighPerfModeEnabled(false);
+        }
+    }
+
+    /* Parent: DeviceInactiveState. Device is inactive, but an app is holding a high perf lock. */
+    class FullHighPerfLockHeldState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
+            mWifiStateMachine.setDriverStart(true);
+            mWifiStateMachine.setHighPerfModeEnabled(true);
+        }
+    }
+
+    /* Parent: DeviceInactiveState. Device is inactive and no app is holding a wifi lock. */
+    class NoLockHeldState extends State {
+        @Override
+        public void enter() {
+            mWifiStateMachine.setDriverStart(false);
+        }
+    }
+
+    private void checkLocksAndTransitionWhenDeviceIdle() {
+        if (mLocks.hasLocks()) {
+            switch (mLocks.getStrongestLockMode()) {
+                case WIFI_MODE_FULL:
+                    transitionTo(mFullLockHeldState);
+                    break;
+                case WIFI_MODE_FULL_HIGH_PERF:
+                    transitionTo(mFullHighPerfLockHeldState);
+                    break;
+                case WIFI_MODE_SCAN_ONLY:
+                    transitionTo(mScanOnlyLockHeldState);
+                    break;
+                default:
+                    loge("Illegal lock " + mLocks.getStrongestLockMode());
+            }
+        } else {
+            if (mSettingsStore.isScanAlwaysAvailable()) {
+                transitionTo(mScanOnlyLockHeldState);
+            } else {
+                transitionTo(mNoLockHeldState);
+            }
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        super.dump(fd, pw, args);
+
+        pw.println("mScreenOff " + mScreenOff);
+        pw.println("mDeviceIdle " + mDeviceIdle);
+        pw.println("mPluggedType " + mPluggedType);
+        pw.println("mIdleMillis " + mIdleMillis);
+        pw.println("mSleepPolicy " + mSleepPolicy);
+    }
+}
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index d675822..f8d5d2e 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -17,15 +17,14 @@
 package com.android.server.wifi;
 
 import android.app.ActivityManager;
-import android.app.AlarmManager;
 import android.app.AppOpsManager;
-import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
@@ -33,12 +32,9 @@
 import android.net.wifi.WifiStateMachine;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiWatchdogStateMachine;
-import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.DhcpResults;
 import android.net.LinkAddress;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.os.Binder;
@@ -62,40 +58,37 @@
 import java.net.Inet4Address;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
+import com.android.internal.R;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.AsyncChannel;
 import com.android.server.am.BatteryStatsService;
-import com.android.internal.R;
-
+import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
+import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
+import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
+import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
+import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
+import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
+import static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
+import static com.android.server.wifi.WifiController.CMD_SET_AP;
+import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
 /**
  * WifiService handles remote WiFi operation requests by implementing
  * the IWifiManager interface.
  *
  * @hide
  */
-//TODO: Clean up multiple locks and implement WifiService
-// as a SM to track soft AP/client/adhoc bring up based
-// on device idle state, airplane mode and boot.
-
 public final class WifiService extends IWifiManager.Stub {
     private static final String TAG = "WifiService";
     private static final boolean DBG = false;
 
-    private final WifiStateMachine mWifiStateMachine;
+    final WifiStateMachine mWifiStateMachine;
 
     private final Context mContext;
 
-    private AlarmManager mAlarmManager;
-    private PendingIntent mIdleIntent;
-    private static final int IDLE_REQUEST = 0;
-    private boolean mScreenOff;
-    private boolean mDeviceIdle;
-    private boolean mEmergencyCallbackMode = false;
-    private int mPluggedType;
-
-    private final LockList mLocks = new LockList();
+    final LockList mLocks = new LockList();
     // some wifi lock statistics
     private int mFullHighPerfLocksAcquired;
     private int mFullHighPerfLocksReleased;
@@ -109,6 +102,9 @@
     private int mMulticastEnabled;
     private int mMulticastDisabled;
 
+    private AtomicBoolean mDeviceProvisioned = new AtomicBoolean();
+    private AtomicBoolean mNotifyScanMode = new AtomicBoolean();
+
     private final IBatteryStats mBatteryStats;
     private final AppOpsManager mAppOps;
 
@@ -119,19 +115,7 @@
     /* Polls traffic stats and notifies clients */
     private WifiTrafficPoller mTrafficPoller;
     /* Tracks the persisted states for wi-fi & airplane mode */
-    private WifiSettingsStore mSettingsStore;
-
-    /**
-     * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a
-     * Settings.Global value is not present. This timeout value is chosen as
-     * the approximate point at which the battery drain caused by Wi-Fi
-     * being enabled but not active exceeds the battery drain caused by
-     * re-establishing a connection to the mobile data network.
-     */
-    private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */
-
-    private static final String ACTION_DEVICE_IDLE =
-            "com.android.server.WifiManager.action.DEVICE_IDLE";
+    final WifiSettingsStore mSettingsStore;
 
     /* The work source (UID) that triggered the current WIFI scan, synchronized
      * on this */
@@ -139,8 +123,6 @@
 
     private boolean mIsReceiverRegistered = false;
 
-    NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", "");
-
     /**
      * Asynchronous channel to WifiStateMachine
      */
@@ -195,7 +177,7 @@
                     break;
                 }
                 default: {
-                    Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
+                    Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
                     break;
                 }
             }
@@ -243,11 +225,6 @@
     }
     WifiStateMachineHandler mWifiStateMachineHandler;
 
-    /**
-     * Temporary for computing UIDS that are responsible for starting WIFI.
-     * Protected by mWifiStateTracker lock.
-     */
-    private final WorkSource mTmpWorkSource = new WorkSource();
     private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
 
     public WifiService(Context context) {
@@ -260,20 +237,26 @@
         mBatteryStats = BatteryStatsService.getService();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
 
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
-        mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
-
         mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
         mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
         mSettingsStore = new WifiSettingsStore(mContext);
 
+        HandlerThread wifiThread = new HandlerThread("WifiService");
+        wifiThread.start();
+        mClientHandler = new ClientHandler(wifiThread.getLooper());
+        mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
+        mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
+        mWifiController.start();
+
+        registerForScanModeChange();
+        registerForDeviceProvisionedChange();
+        registerForNotifyUserOnScanModeChange();
         mContext.registerReceiver(
                 new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
                         if (mSettingsStore.handleAirplaneModeToggled()) {
-                            updateWifiState();
+                            mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
                         }
                     }
                 },
@@ -289,13 +272,10 @@
                         }
                     }
                 }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
-
-        HandlerThread wifiThread = new HandlerThread("WifiService");
-        wifiThread.start();
-        mClientHandler = new ClientHandler(wifiThread.getLooper());
-        mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
     }
 
+    private WifiController mWifiController;
+
     /** Tell battery stats about a new WIFI scan */
     private void noteScanStart() {
         WorkSource scanWorkSource = null;
@@ -342,7 +322,7 @@
      */
     public void checkAndStartWifi() {
         /* Check if wi-fi needs to be enabled */
-        boolean wifiEnabled = mSettingsStore.shouldWifiBeEnabled();
+        boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
 
@@ -422,6 +402,16 @@
 
         long ident = Binder.clearCallingIdentity();
         try {
+
+            /* Turning off Wi-Fi when scans are still available */
+            if (!enable && isScanningAlwaysAvailable()) {
+                /* Notify if device is provisioned and user has not opted out of the notification */
+                if (mNotifyScanMode.get() && mDeviceProvisioned.get()) {
+                    Intent intent = new Intent(WifiManager.ACTION_NOTIFY_SCAN_ALWAYS_AVAILABLE);
+                    mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
+                }
+            }
+
             if (! mSettingsStore.handleWifiToggled(enable)) {
                 // Nothing to do if wifi cannot be toggled
                 return true;
@@ -430,11 +420,7 @@
             Binder.restoreCallingIdentity(ident);
         }
 
-        if (enable) {
-            reportStartWorkSource();
-        }
-
-        mWifiStateMachine.setWifiEnabled(enable);
+        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
 
         if (enable) {
             if (!mIsReceiverRegistered) {
@@ -470,7 +456,7 @@
      */
     public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
         enforceChangePermission();
-        mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
+        mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
     }
 
     /**
@@ -507,6 +493,16 @@
     }
 
     /**
+     * @param enable {@code true} to enable, {@code false} to disable.
+     * @return {@code true} if the enable/disable operation was
+     *         started or is already in the queue.
+     */
+    public boolean isScanningAlwaysAvailable() {
+        enforceAccessPermission();
+        return mSettingsStore.isScanAlwaysAvailable();
+    }
+
+    /**
      * see {@link android.net.wifi.WifiManager#disconnect()}
      */
     public void disconnect() {
@@ -777,7 +773,7 @@
          * of WifiLock & device idle status unless wifi enabled status is toggled
          */
 
-        mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
+        mWifiStateMachine.setDriverStart(true);
         mWifiStateMachine.reconnectCommand();
     }
 
@@ -796,7 +792,7 @@
          * TODO: if a stop is issued, wifi is brought up only by startWifi
          * unless wifi enabled status is toggled
          */
-        mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
+        mWifiStateMachine.setDriverStart(false);
     }
 
     /**
@@ -848,175 +844,84 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-
-            long idleMillis =
-                Settings.Global.getLong(mContext.getContentResolver(),
-                                        Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
-            int stayAwakeConditions =
-                Settings.Global.getInt(mContext.getContentResolver(),
-                                       Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             if (action.equals(Intent.ACTION_SCREEN_ON)) {
-                if (DBG) {
-                    Slog.d(TAG, "ACTION_SCREEN_ON");
-                }
-                mAlarmManager.cancel(mIdleIntent);
-                mScreenOff = false;
-                setDeviceIdleAndUpdateWifi(false);
+                mWifiController.sendMessage(CMD_SCREEN_ON);
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
-                if (DBG) {
-                    Slog.d(TAG, "ACTION_SCREEN_OFF");
-                }
-                mScreenOff = true;
-                /*
-                 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
-                 * AND the "stay on while plugged in" setting doesn't match the
-                 * current power conditions (i.e, not plugged in, plugged in to USB,
-                 * or plugged in to AC).
-                 */
-                if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) {
-                    //Delayed shutdown if wifi is connected
-                    if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) {
-                        if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms");
-                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
-                                + idleMillis, mIdleIntent);
-                    } else {
-                        setDeviceIdleAndUpdateWifi(true);
-                    }
-                }
-            } else if (action.equals(ACTION_DEVICE_IDLE)) {
-                setDeviceIdleAndUpdateWifi(true);
+                mWifiController.sendMessage(CMD_SCREEN_OFF);
             } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-                /*
-                 * Set a timer to put Wi-Fi to sleep, but only if the screen is off
-                 * AND we are transitioning from a state in which the device was supposed
-                 * to stay awake to a state in which it is not supposed to stay awake.
-                 * If "stay awake" state is not changing, we do nothing, to avoid resetting
-                 * the already-set timer.
-                 */
                 int pluggedType = intent.getIntExtra("plugged", 0);
-                if (DBG) {
-                    Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType);
-                }
-                if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) &&
-                        !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) {
-                    long triggerTime = System.currentTimeMillis() + idleMillis;
-                    if (DBG) {
-                        Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms");
-                    }
-                    mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
-                }
-
-                mPluggedType = pluggedType;
+                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
             } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
                         BluetoothAdapter.STATE_DISCONNECTED);
                 mWifiStateMachine.sendBluetoothAdapterStateChange(state);
             } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
-                mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false);
-                updateWifiState();
+                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
+                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
             }
         }
-
-        /**
-         * Determines whether the Wi-Fi chipset should stay awake or be put to
-         * sleep. Looks at the setting for the sleep policy and the current
-         * conditions.
-         *
-         * @see #shouldDeviceStayAwake(int, int)
-         */
-        private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) {
-            //Never sleep as long as the user has not changed the settings
-            int wifiSleepPolicy = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.WIFI_SLEEP_POLICY,
-                    Settings.Global.WIFI_SLEEP_POLICY_NEVER);
-
-            if (wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
-                // Never sleep
-                return true;
-            } else if ((wifiSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) &&
-                    (pluggedType != 0)) {
-                // Never sleep while plugged, and we're plugged
-                return true;
-            } else {
-                // Default
-                return shouldDeviceStayAwake(stayAwakeConditions, pluggedType);
-            }
-        }
-
-        /**
-         * Determine whether the bit value corresponding to {@code pluggedType} is set in
-         * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
-         * of {@code 0} isn't really a plugged type, but rather an indication that the
-         * device isn't plugged in at all, there is no bit value corresponding to a
-         * {@code pluggedType} value of {@code 0}. That is why we shift by
-         * {@code pluggedType - 1} instead of by {@code pluggedType}.
-         * @param stayAwakeConditions a bit string specifying which "plugged types" should
-         * keep the device (and hence Wi-Fi) awake.
-         * @param pluggedType the type of plug (USB, AC, or none) for which the check is
-         * being made
-         * @return {@code true} if {@code pluggedType} indicates that the device is
-         * supposed to stay awake, {@code false} otherwise.
-         */
-        private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) {
-            return (stayAwakeConditions & pluggedType) != 0;
-        }
     };
 
-    private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) {
-        mDeviceIdle = deviceIdle;
-        reportStartWorkSource();
-        updateWifiState();
+    /**
+     * Observes settings changes to scan always mode.
+     */
+    private void registerForScanModeChange() {
+        ContentObserver contentObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
+                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
+            }
+        };
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
+                false, contentObserver);
     }
 
-    private synchronized void reportStartWorkSource() {
-        mTmpWorkSource.clear();
-        if (mDeviceIdle) {
-            for (int i=0; i<mLocks.mList.size(); i++) {
-                mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource);
-            }
-        }
-        mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
+    private void getPersistedDeviceProvisioned() {
+        mDeviceProvisioned.set(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0);
     }
 
-    private void updateWifiState() {
-        boolean lockHeld = mLocks.hasLocks();
-        int strongestLockMode = WifiManager.WIFI_MODE_FULL;
-        boolean wifiShouldBeStarted;
+    private void getPersistedNotifyScanMode() {
+        mNotifyScanMode.set(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NOTIFY_SCAN_ALWAYS_AVAILABLE, 1) == 1);
+    }
 
-        if (mEmergencyCallbackMode) {
-            wifiShouldBeStarted = false;
-        } else {
-            wifiShouldBeStarted = !mDeviceIdle || lockHeld;
-        }
-
-        if (lockHeld) {
-            strongestLockMode = mLocks.getStrongestLockMode();
-        }
-        /* If device is not idle, lockmode cannot be scan only */
-        if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
-            strongestLockMode = WifiManager.WIFI_MODE_FULL;
-        }
-
-        /* Disable tethering when airplane mode is enabled */
-        if (mSettingsStore.isAirplaneModeOn()) {
-            mWifiStateMachine.setWifiApEnabled(null, false);
-        }
-
-        if (mSettingsStore.shouldWifiBeEnabled()) {
-            if (wifiShouldBeStarted) {
-                reportStartWorkSource();
-                mWifiStateMachine.setWifiEnabled(true);
-                mWifiStateMachine.setScanOnlyMode(
-                        strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
-                mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode);
-                mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode
-                        == WifiManager.WIFI_MODE_FULL_HIGH_PERF);
-            } else {
-                mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode);
+    /**
+     * Observes settings changes to notify the user when scan mode is active and
+     * Wi-Fi is turned off
+     */
+    private void registerForNotifyUserOnScanModeChange() {
+            ContentObserver contentObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                getPersistedNotifyScanMode();
             }
-        } else {
-            mWifiStateMachine.setWifiEnabled(false);
-        }
+        };
+
+        getPersistedNotifyScanMode();
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.WIFI_NOTIFY_SCAN_ALWAYS_AVAILABLE),
+                false, contentObserver);
+    }
+
+    /*
+     * Observes settings changes device provisioned status
+     */
+    private void registerForDeviceProvisionedChange() {
+       ContentObserver contentObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                getPersistedDeviceProvisioned();
+            }
+        };
+
+        getPersistedDeviceProvisioned();
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
+                false, contentObserver);
     }
 
     private void registerForBroadcasts() {
@@ -1024,7 +929,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        intentFilter.addAction(ACTION_DEVICE_IDLE);
+        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
         intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         mContext.registerReceiver(mReceiver, intentFilter);
@@ -1043,12 +948,11 @@
         pw.println("Stay-awake conditions: " +
                 Settings.Global.getInt(mContext.getContentResolver(),
                                        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
-        pw.println("mScreenOff " + mScreenOff);
-        pw.println("mDeviceIdle " + mDeviceIdle);
-        pw.println("mPluggedType " + mPluggedType);
-        pw.println("mEmergencyCallbackMode " + mEmergencyCallbackMode);
+        pw.println("mDeviceProvisioned " + mDeviceProvisioned.get());
+        pw.println("mNotifyScanMode " + mNotifyScanMode.get());
         pw.println("mMulticastEnabled " + mMulticastEnabled);
         pw.println("mMulticastDisabled " + mMulticastDisabled);
+        mWifiController.dump(fd, pw, args);
         mSettingsStore.dump(fd, pw, args);
         mNotificationController.dump(fd, pw, args);
         mTrafficPoller.dump(fd, pw, args);
@@ -1099,18 +1003,18 @@
         }
     }
 
-    private class LockList {
+    class LockList {
         private List<WifiLock> mList;
 
         private LockList() {
             mList = new ArrayList<WifiLock>();
         }
 
-        private synchronized boolean hasLocks() {
+        synchronized boolean hasLocks() {
             return !mList.isEmpty();
         }
 
-        private synchronized int getStrongestLockMode() {
+        synchronized int getStrongestLockMode() {
             if (mList.isEmpty()) {
                 return WifiManager.WIFI_MODE_FULL;
             }
@@ -1126,6 +1030,12 @@
             return WifiManager.WIFI_MODE_SCAN_ONLY;
         }
 
+        synchronized void updateWorkSource(WorkSource ws) {
+            for (int i = 0; i < mLocks.mList.size(); i++) {
+                ws.add(mLocks.mList.get(i).mWorkSource);
+            }
+        }
+
         private void addLock(WifiLock lock) {
             if (findLockByBinder(lock.mBinder) < 0) {
                 mList.add(lock);
@@ -1145,9 +1055,10 @@
 
         private int findLockByBinder(IBinder binder) {
             int size = mList.size();
-            for (int i = size - 1; i >= 0; i--)
+            for (int i = size - 1; i >= 0; i--) {
                 if (mList.get(i).mBinder == binder)
                     return i;
+            }
             return -1;
         }
 
@@ -1231,12 +1142,7 @@
                 ++mScanLocksAcquired;
                 break;
             }
-
-            // Be aggressive about adding new locks into the accounted state...
-            // we want to over-report rather than under-report.
-            reportStartWorkSource();
-
-            updateWifiState();
+            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
             return true;
         } catch (RemoteException e) {
             return false;
@@ -1303,11 +1209,8 @@
                         ++mScanLocksReleased;
                         break;
                 }
+                mWifiController.sendMessage(CMD_LOCKS_CHANGED);
             }
-
-            // TODO - should this only happen if you hadLock?
-            updateWifiState();
-
         } catch (RemoteException e) {
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/java/com/android/server/wifi/WifiSettingsStore.java
index d7c8752..3ff8061 100644
--- a/services/java/com/android/server/wifi/WifiSettingsStore.java
+++ b/services/java/com/android/server/wifi/WifiSettingsStore.java
@@ -37,7 +37,11 @@
     private int mPersistWifiState = WIFI_DISABLED;
     /* Tracks current airplane mode state */
     private boolean mAirplaneModeOn = false;
-    /* Tracks whether wifi is enabled from WifiStateMachine's perspective */
+
+    /* Tracks the setting of scan being available even when wi-fi is turned off
+     */
+    private boolean mScanAlwaysAvailable;
+
     private final Context mContext;
 
     /* Tracks if we have checked the saved wi-fi state after boot */
@@ -47,9 +51,10 @@
         mContext = context;
         mAirplaneModeOn = getPersistedAirplaneModeOn();
         mPersistWifiState = getPersistedWifiState();
+        mScanAlwaysAvailable = getPersistedScanAlwaysAvailable();
     }
 
-    synchronized boolean shouldWifiBeEnabled() {
+    synchronized boolean isWifiToggleEnabled() {
         if (!mCheckSavedStateAtBoot) {
             mCheckSavedStateAtBoot = true;
             if (testAndClearWifiSavedState()) return true;
@@ -70,6 +75,10 @@
        return mAirplaneModeOn;
     }
 
+    synchronized boolean isScanAlwaysAvailable() {
+        return mScanAlwaysAvailable;
+    }
+
     synchronized boolean handleWifiToggled(boolean wifiEnabled) {
         // Can Wi-Fi be toggled in airplane mode ?
         if (mAirplaneModeOn && !isAirplaneToggleable()) {
@@ -114,6 +123,10 @@
         return true;
     }
 
+    synchronized void handleWifiScanAlwaysAvailableToggled() {
+        mScanAlwaysAvailable = getPersistedScanAlwaysAvailable();
+    }
+
     void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("mPersistWifiState " + mPersistWifiState);
         pw.println("mAirplaneModeOn " + mAirplaneModeOn);
@@ -175,4 +188,10 @@
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
     }
+
+    private boolean getPersistedScanAlwaysAvailable() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
+                0) == 1;
+    }
 }
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 297324b..6293dc6 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -4,6 +4,7 @@
 
 import android.graphics.Matrix;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -30,6 +31,11 @@
     // Protect with mAnimator.
     boolean freezingScreen;
 
+    /**
+     * How long we last kept the screen frozen.
+     */
+    int lastFreezeDuration;
+
     // Offset to the window of all layers in the token, for use by
     // AppWindowToken animations.
     int animLayerAdjustment;
@@ -287,6 +293,10 @@
         pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
                 pw.print(" allDrawn="); pw.print(allDrawn);
                 pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
+        if (lastFreezeDuration != 0) {
+            pw.print(prefix); pw.print("lastFreezeDuration=");
+                    TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
+        }
         if (animating || animation != null) {
             pw.print(prefix); pw.print("animating="); pw.println(animating);
             pw.print(prefix); pw.print("animation="); pw.println(animation);
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 3708df2..b2fbec1 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -234,6 +234,7 @@
                 mSurfaceControl.setLayer(FREEZE_LAYER + 1);
                 mSurfaceControl.setAlpha(0);
                 mSurfaceControl.show();
+                sur.destroy();
             } catch (SurfaceControl.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate freeze surface", e);
             }
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 3964782..054a075 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -70,6 +70,7 @@
     int mAboveUniverseLayer = 0;
 
     int mBulkUpdateParams = 0;
+    Object mLastWindowFreezeSource;
 
     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
             new SparseArray<WindowAnimator.DisplayContentsAnimator>();
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index cfefadd..1d1fda5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -43,6 +43,7 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
 import android.app.AppOpsManager;
+import android.util.TimeUtils;
 import android.view.IWindowId;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.policy.PolicyManager;
@@ -76,6 +77,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -282,6 +284,8 @@
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
+    private static final int MAX_SCREENSHOT_RETRIES = 3;
+
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
     private final boolean mHeadless;
@@ -461,6 +465,9 @@
 
     boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
+    long mDisplayFreezeTime = 0;
+    int mLastDisplayFreezeDuration = 0;
+    Object mLastFinishedFreezeSource = null;
     boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
     boolean mClientFreezingScreen = false;
@@ -579,6 +586,7 @@
         boolean mWallpaperForceHidingChanged = false;
         boolean mWallpaperMayChange = false;
         boolean mOrientationChangeComplete = true;
+        Object mLastWindowFreezeSource = null;
         private Session mHoldScreen = null;
         private boolean mObscured = false;
         boolean mDimming = false;
@@ -1481,7 +1489,11 @@
                     pos++;
                 }
                 if (pos >= N) {
-                    // All is good!
+                    // Z order is good.
+                    // The IM target window may be changed, so update the mTargetAppToken.
+                    if (imWin != null) {
+                        imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
+                    }
                     return false;
                 }
             }
@@ -3583,7 +3595,10 @@
 
         synchronized(mWindowMap) {
             mCurConfiguration = new Configuration(config);
-            mWaitingForConfig = false;
+            if (mWaitingForConfig) {
+                mWaitingForConfig = false;
+                mLastFinishedFreezeSource = "new-config";
+            }
             performLayoutAndPlaceSurfacesLocked();
         }
     }
@@ -4202,6 +4217,7 @@
                         w.mOrientationChanging = true;
                         mInnerFields.mOrientationChangeComplete = false;
                     }
+                    w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
                     w.mDisplayContent.layoutNeeded = true;
                 }
@@ -4209,7 +4225,10 @@
             if (force || unfrozeWindows) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
                 wtoken.mAppAnimator.freezingScreen = false;
+                wtoken.mAppAnimator.lastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                        - mDisplayFreezeTime);
                 mAppsFreezingScreen--;
+                mLastFinishedFreezeSource = wtoken;
             }
             if (unfreezeSurfaceNow) {
                 if (unfrozeWindows) {
@@ -4235,6 +4254,7 @@
         if (!wtoken.hiddenRequested) {
             if (!wtoken.mAppAnimator.freezingScreen) {
                 wtoken.mAppAnimator.freezingScreen = true;
+                wtoken.mAppAnimator.lastFreezeDuration = 0;
                 mAppsFreezingScreen++;
                 if (mAppsFreezingScreen == 1) {
                     startFreezingDisplayLocked(false, 0, 0);
@@ -4743,6 +4763,7 @@
         synchronized(mWindowMap) {
             if (mClientFreezingScreen) {
                 mClientFreezingScreen = false;
+                mLastFinishedFreezeSource = "client";
                 final long origId = Binder.clearCallingIdentity();
                 try {
                     stopFreezingDisplayLocked();
@@ -5273,138 +5294,193 @@
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
 
-        Bitmap rawss;
+        Bitmap rawss = null;
 
         int maxLayer = 0;
         final Rect frame = new Rect();
 
-        float scale;
+        float scale = 0;
         int dw, dh;
-        int rot;
+        int rot = Surface.ROTATION_0;
 
-        synchronized(mWindowMap) {
-            long ident = Binder.clearCallingIdentity();
+        boolean screenshotReady;
+        int minLayer;
+        if (appToken == null) {
+            screenshotReady = true;
+            minLayer = 0;
+        } else {
+            screenshotReady = false;
+            minLayer = Integer.MAX_VALUE;
+        }
 
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent == null) {
-                return null;
+        int retryCount = 0;
+        WindowState appWin = null;
+
+        do {
+            if (retryCount++ > 0) {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                }
             }
-            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-            dw = displayInfo.logicalWidth;
-            dh = displayInfo.logicalHeight;
-
-            int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
-                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
-            aboveAppLayer += TYPE_LAYER_MULTIPLIER;
-
-            boolean isImeTarget = mInputMethodTarget != null
-                    && mInputMethodTarget.mAppToken != null
-                    && mInputMethodTarget.mAppToken.appToken != null
-                    && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
-
-            // Figure out the part of the screen that is actually the app.
-            boolean including = false;
-            final WindowList windows = displayContent.getWindowList();
-            for (int i = windows.size() - 1; i >= 0; i--) {
-                WindowState ws = windows.get(i);
-                if (!ws.mHasSurface) {
-                    continue;
+            synchronized(mWindowMap) {
+                final DisplayContent displayContent = getDisplayContentLocked(displayId);
+                if (displayContent == null) {
+                    return null;
                 }
-                if (ws.mLayer >= aboveAppLayer) {
-                    continue;
-                }
-                // When we will skip windows: when we are not including
-                // ones behind a window we didn't skip, and we are actually
-                // taking a screenshot of a specific app.
-                if (!including && appToken != null) {
-                    // Also, we can possibly skip this window if it is not
-                    // an IME target or the application for the screenshot
-                    // is not the current IME target.
-                    if (!ws.mIsImWindow || !isImeTarget) {
-                        // And finally, this window is of no interest if it
-                        // is not associated with the screenshot app.
-                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
-                            continue;
+                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                dw = displayInfo.logicalWidth;
+                dh = displayInfo.logicalHeight;
+
+                int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
+                        * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
+                aboveAppLayer += TYPE_LAYER_MULTIPLIER;
+
+                boolean isImeTarget = mInputMethodTarget != null
+                        && mInputMethodTarget.mAppToken != null
+                        && mInputMethodTarget.mAppToken.appToken != null
+                        && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
+
+                // Figure out the part of the screen that is actually the app.
+                boolean including = false;
+                appWin = null;
+                final WindowList windows = displayContent.getWindowList();
+                for (int i = windows.size() - 1; i >= 0; i--) {
+                    WindowState ws = windows.get(i);
+                    if (!ws.mHasSurface) {
+                        continue;
+                    }
+                    if (ws.mLayer >= aboveAppLayer) {
+                        continue;
+                    }
+                    // When we will skip windows: when we are not including
+                    // ones behind a window we didn't skip, and we are actually
+                    // taking a screenshot of a specific app.
+                    if (!including && appToken != null) {
+                        // Also, we can possibly skip this window if it is not
+                        // an IME target or the application for the screenshot
+                        // is not the current IME target.
+                        if (!ws.mIsImWindow || !isImeTarget) {
+                            // And finally, this window is of no interest if it
+                            // is not associated with the screenshot app.
+                            if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
+                                continue;
+                            }
+                            appWin = ws;
                         }
                     }
+
+                    // We keep on including windows until we go past a full-screen
+                    // window.
+                    boolean fullscreen = ws.isFullscreen(dw, dh);
+                    including = !ws.mIsImWindow && !fullscreen;
+
+                    final WindowStateAnimator winAnim = ws.mWinAnimator;
+                    if (maxLayer < winAnim.mSurfaceLayer) {
+                        maxLayer = winAnim.mSurfaceLayer;
+                    }
+                    if (minLayer > winAnim.mSurfaceLayer) {
+                        minLayer = winAnim.mSurfaceLayer;
+                    }
+
+                    // Don't include wallpaper in bounds calculation
+                    if (!ws.mIsWallpaper) {
+                        final Rect wf = ws.mFrame;
+                        final Rect cr = ws.mContentInsets;
+                        int left = wf.left + cr.left;
+                        int top = wf.top + cr.top;
+                        int right = wf.right - cr.right;
+                        int bottom = wf.bottom - cr.bottom;
+                        frame.union(left, top, right, bottom);
+                    }
+
+                    if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
+                            ws.isDisplayedLw()) {
+                        screenshotReady = true;
+                    }
+
+                    if (fullscreen) {
+                        // No point in continuing down through windows.
+                        break;
+                    }
                 }
 
-                // We keep on including windows until we go past a full-screen
-                // window.
-                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
-
-                if (maxLayer < ws.mWinAnimator.mSurfaceLayer) {
-                    maxLayer = ws.mWinAnimator.mSurfaceLayer;
+                if (appToken != null && appWin == null) {
+                    // Can't find a window to snapshot.
+                    if (DEBUG_SCREENSHOT) Slog.i(TAG,
+                            "Screenshot: Couldn't find a surface matching " + appToken);
+                    return null;
+                }
+                if (!screenshotReady) {
+                    // Delay and hope that window gets drawn.
+                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken
+                            + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
+                    continue;
                 }
 
-                // Don't include wallpaper in bounds calculation
-                if (!ws.mIsWallpaper) {
-                    final Rect wf = ws.mFrame;
-                    final Rect cr = ws.mContentInsets;
-                    int left = wf.left + cr.left;
-                    int top = wf.top + cr.top;
-                    int right = wf.right - cr.right;
-                    int bottom = wf.bottom - cr.bottom;
-                    frame.union(left, top, right, bottom);
+                // Constrain frame to the screen size.
+                frame.intersect(0, 0, dw, dh);
+
+                if (frame.isEmpty() || maxLayer == 0) {
+                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken
+                            + ": returning null frame=" + frame.toShortString() + " maxLayer="
+                            + maxLayer);
+                    return null;
                 }
-            }
-            Binder.restoreCallingIdentity(ident);
 
-            // Constrain frame to the screen size.
-            frame.intersect(0, 0, dw, dh);
+                // The screenshot API does not apply the current screen rotation.
+                rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
+                int fw = frame.width();
+                int fh = frame.height();
 
-            if (frame.isEmpty() || maxLayer == 0) {
-                return null;
-            }
-
-            // The screenshot API does not apply the current screen rotation.
-            rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
-            int fw = frame.width();
-            int fh = frame.height();
-
-            // Constrain thumbnail to smaller of screen width or height. Assumes aspect
-            // of thumbnail is the same as the screen (in landscape) or square.
-            float targetWidthScale = width / (float) fw;
-            float targetHeightScale = height / (float) fh;
-            if (dw <= dh) {
-                scale = targetWidthScale;
-                // If aspect of thumbnail is the same as the screen (in landscape),
-                // select the slightly larger value so we fill the entire bitmap
-                if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
-                    scale = targetHeightScale;
-                }
-            } else {
-                scale = targetHeightScale;
-                // If aspect of thumbnail is the same as the screen (in landscape),
-                // select the slightly larger value so we fill the entire bitmap
-                if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
+                // Constrain thumbnail to smaller of screen width or height. Assumes aspect
+                // of thumbnail is the same as the screen (in landscape) or square.
+                float targetWidthScale = width / (float) fw;
+                float targetHeightScale = height / (float) fh;
+                if (dw <= dh) {
                     scale = targetWidthScale;
+                    // If aspect of thumbnail is the same as the screen (in landscape),
+                    // select the slightly larger value so we fill the entire bitmap
+                    if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
+                        scale = targetHeightScale;
+                    }
+                } else {
+                    scale = targetHeightScale;
+                    // If aspect of thumbnail is the same as the screen (in landscape),
+                    // select the slightly larger value so we fill the entire bitmap
+                    if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
+                        scale = targetWidthScale;
+                    }
                 }
-            }
 
-            // The screen shot will contain the entire screen.
-            dw = (int)(dw*scale);
-            dh = (int)(dh*scale);
-            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
-                int tmp = dw;
-                dw = dh;
-                dh = tmp;
-                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
-            }
-            if (DEBUG_SCREENSHOT) {
-                Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
-                for (int i = 0; i < windows.size(); i++) {
-                    WindowState win = windows.get(i);
-                    Slog.i(TAG, win + ": " + win.mLayer
-                            + " animLayer=" + win.mWinAnimator.mAnimLayer
-                            + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
+                // The screen shot will contain the entire screen.
+                dw = (int)(dw*scale);
+                dh = (int)(dh*scale);
+                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+                    int tmp = dw;
+                    dw = dh;
+                    dh = tmp;
+                    rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
                 }
+                if (DEBUG_SCREENSHOT) {
+                    Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
+                            + maxLayer + " appToken=" + appToken);
+                    for (int i = 0; i < windows.size(); i++) {
+                        WindowState win = windows.get(i);
+                        Slog.i(TAG, win + ": " + win.mLayer
+                                + " animLayer=" + win.mWinAnimator.mAnimLayer
+                                + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
+                    }
+                }
+                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
             }
-            rawss = SurfaceControl.screenshot(dw, dh, 0, maxLayer);
-        }
+        } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
+        if (retryCount > MAX_SCREENSHOT_RETRIES)  Slog.i(TAG, "Screenshot max retries " +
+                retryCount + " of " + appToken + " appWin=" + (appWin == null ?
+                        "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState)));
 
         if (rawss == null) {
-            Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
+            Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
                     + ") to layer " + maxLayer);
             return null;
         }
@@ -5417,6 +5493,24 @@
         canvas.drawBitmap(rawss, matrix, null);
         canvas.setBitmap(null);
 
+        if (true || DEBUG_SCREENSHOT) {
+            // TEST IF IT's ALL BLACK
+            int[] buffer = new int[bm.getWidth() * bm.getHeight()];
+            bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
+            boolean allBlack = true;
+            for (int i = 0; i < buffer.length; i++) {
+                if (buffer[i] != Color.BLACK) {
+                    allBlack = false;
+                    break;
+                }
+            }
+            if (allBlack) {
+                Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
+                        (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
+                        " minLayer=" + minLayer + " maxLayer=" + maxLayer);
+            }
+        }
+
         rawss.recycle();
         return bm;
     }
@@ -5662,6 +5756,7 @@
                 w.mOrientationChanging = true;
                 mInnerFields.mOrientationChangeComplete = false;
             }
+            w.mLastFreezeDuration = 0;
         }
 
         for (int i=mRotationWatchers.size()-1; i>=0; i--) {
@@ -5722,6 +5817,19 @@
         }
     }
 
+    @Override
+    public void removeRotationWatcher(IRotationWatcher watcher) {
+        final IBinder watcherBinder = watcher.asBinder();
+        synchronized (mWindowMap) {
+            for (int i=0; i<mRotationWatchers.size(); i++) {
+                if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
+                    mRotationWatchers.remove(i);
+                    i--;
+                }
+            }
+        }
+    }
+
     /**
      * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
      * theme attribute) on devices that feature a physical options menu key attempt to position
@@ -6147,6 +6255,7 @@
             if (config == null && mWaitingForConfig) {
                 // Nothing changed but we are waiting for something... stop that!
                 mWaitingForConfig = false;
+                mLastFinishedFreezeSource = "new-config";
                 performLayoutAndPlaceSurfacesLocked();
             }
             return config;
@@ -6943,6 +7052,8 @@
                             WindowState w = windows.get(i);
                             if (w.mOrientationChanging) {
                                 w.mOrientationChanging = false;
+                                w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                                        - mDisplayFreezeTime);
                                 Slog.w(TAG, "Force clearing orientation change: " + w);
                             }
                         }
@@ -7019,6 +7130,7 @@
                     synchronized (mWindowMap) {
                         if (mClientFreezingScreen) {
                             mClientFreezingScreen = false;
+                            mLastFinishedFreezeSource = "client-timeout";
                             stopFreezingDisplayLocked();
                         }
                     }
@@ -7210,6 +7322,7 @@
         return false;
     }
 
+    @Override
     public void getInitialDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
@@ -7223,6 +7336,19 @@
     }
 
     @Override
+    public void getBaseDisplaySize(int displayId, Point size) {
+        synchronized (mWindowMap) {
+            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            if (displayContent != null) {
+                synchronized(displayContent.mDisplaySizeLock) {
+                    size.x = displayContent.mBaseDisplayWidth;
+                    size.y = displayContent.mBaseDisplayHeight;
+                }
+            }
+        }
+    }
+
+    @Override
     public void setForcedDisplaySize(int displayId, int width, int height) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
@@ -7325,6 +7451,32 @@
     }
 
     @Override
+    public int getInitialDisplayDensity(int displayId) {
+        synchronized (mWindowMap) {
+            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            if (displayContent != null) {
+                synchronized(displayContent.mDisplaySizeLock) {
+                    return displayContent.mInitialDisplayDensity;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public int getBaseDisplayDensity(int displayId) {
+        synchronized (mWindowMap) {
+            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            if (displayContent != null) {
+                synchronized(displayContent.mDisplaySizeLock) {
+                    return displayContent.mBaseDisplayDensity;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @Override
     public void setForcedDisplayDensity(int displayId, int density) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
@@ -7404,6 +7556,7 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
+    @Override
     public void setOverscan(int displayId, int left, int top, int right, int bottom) {
         if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
@@ -7895,6 +8048,7 @@
             if (DEBUG_ORIENTATION) Slog.v(TAG,
                     "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
+            w.mLastFreezeDuration = 0;
             mInnerFields.mOrientationChangeComplete = false;
             if (!mWindowsFreezingScreen) {
                 mWindowsFreezingScreen = true;
@@ -8283,6 +8437,8 @@
                             "Orientation not waiting for draw in "
                             + w + ", surface " + winAnimator.mSurfaceControl);
                     w.mOrientationChanging = false;
+                    w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                            - mDisplayFreezeTime);
                 }
             }
         }
@@ -8796,6 +8952,8 @@
                 winAnimator.mSurfaceResized = false;
             } catch (RemoteException e) {
                 win.mOrientationChanging = false;
+                win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                        - mDisplayFreezeTime);
             }
             mResizingWindows.remove(i);
         }
@@ -8806,6 +8964,7 @@
         if (mInnerFields.mOrientationChangeComplete) {
             if (mWindowsFreezingScreen) {
                 mWindowsFreezingScreen = false;
+                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
             }
             stopFreezingDisplayLocked();
@@ -9092,6 +9251,7 @@
             mInnerFields.mOrientationChangeComplete = false;
         } else {
             mInnerFields.mOrientationChangeComplete = true;
+            mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
             if (mWindowsFreezingScreen) {
                 doRequest = true;
             }
@@ -9364,6 +9524,8 @@
         mScreenFrozenLock.acquire();
 
         mDisplayFrozen = true;
+        mDisplayFreezeTime = SystemClock.elapsedRealtime();
+        mLastFinishedFreezeSource = null;
 
         mInputMonitor.freezeInputDispatchingLw();
 
@@ -9418,6 +9580,15 @@
         }
 
         mDisplayFrozen = false;
+        mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("Screen frozen for ");
+        TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
+        if (mLastFinishedFreezeSource != null) {
+            sb.append(" due to ");
+            sb.append(mLastFinishedFreezeSource);
+        }
+        Slog.i(TAG, sb.toString());
         mH.removeMessages(H.APP_FREEZE_TIMEOUT);
         mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
         if (PROFILE_ORIENTATION) {
@@ -9942,6 +10113,13 @@
         }
         pw.print("  mInTouchMode="); pw.print(mInTouchMode);
                 pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
+        pw.print("  mLastDisplayFreezeDuration=");
+                TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
+                if ( mLastFinishedFreezeSource != null) {
+                    pw.print(" due to ");
+                    pw.print(mLastFinishedFreezeSource);
+                }
+                pw.println();
         if (dumpAll) {
             pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
                     pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 506fcec..ca060f4 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -26,6 +26,7 @@
 
 import android.app.AppOpsManager;
 import android.os.RemoteCallbackList;
+import android.util.TimeUtils;
 import android.view.IWindowFocusObserver;
 import android.view.IWindowId;
 import com.android.server.input.InputWindowHandle;
@@ -266,6 +267,11 @@
      */
     boolean mOrientationChanging;
 
+    /**
+     * How long we last kept the screen frozen.
+     */
+    int mLastFreezeDuration;
+
     /** Is this window now (or just being) removed? */
     boolean mRemoved;
 
@@ -1387,6 +1393,10 @@
                     pw.print(" mAppFreezing="); pw.print(mAppFreezing);
                     pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen);
         }
+        if (mLastFreezeDuration != 0) {
+            pw.print(prefix); pw.print("mLastFreezeDuration=");
+                    TimeUtils.formatDuration(mLastFreezeDuration, pw); pw.println();
+        }
         if (mHScale != 1 || mVScale != 1) {
             pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
                     pw.print(" mVScale="); pw.println(mVScale);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 3a9f7cb..452f76d 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1307,6 +1307,7 @@
             if (w.mOrientationChanging) {
                 if (!w.isDrawnLw()) {
                     mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
+                    mAnimator.mLastWindowFreezeSource = w;
                     if (DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation continue waiting for draw in " + w);
                 } else {
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index d097a93..b313d48 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -32,6 +32,7 @@
     libandroid_runtime \
     libandroidfw \
     libcutils \
+    liblog \
     libhardware \
     libhardware_legacy \
     libnativehelper \
diff --git a/services/jni/com_android_server_input_InputApplicationHandle.cpp b/services/jni/com_android_server_input_InputApplicationHandle.cpp
index 0109430..b9681ab 100644
--- a/services/jni/com_android_server_input_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -97,7 +97,7 @@
     } else {
         jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj);
         handle = new NativeInputApplicationHandle(objWeak);
-        handle->incStrong(inputApplicationHandleObj);
+        handle->incStrong((void*)android_server_InputApplicationHandle_getHandle);
         env->SetIntField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr,
                 reinterpret_cast<int>(handle));
     }
@@ -115,7 +115,7 @@
         env->SetIntField(obj, gInputApplicationHandleClassInfo.ptr, 0);
 
         NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
-        handle->decStrong(obj);
+        handle->decStrong((void*)android_server_InputApplicationHandle_getHandle);
     }
 }
 
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 57803e3..09e5be4 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -982,7 +982,7 @@
 
     NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
             messageQueue->getLooper());
-    im->incStrong(serviceObj);
+    im->incStrong(0);
     return reinterpret_cast<jint>(im);
 }
 
diff --git a/services/jni/com_android_server_input_InputWindowHandle.cpp b/services/jni/com_android_server_input_InputWindowHandle.cpp
index 6692994..bbb27d3 100644
--- a/services/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_input_InputWindowHandle.cpp
@@ -183,7 +183,7 @@
 
         jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
         handle = new NativeInputWindowHandle(inputApplicationHandle, objWeak);
-        handle->incStrong(inputWindowHandleObj);
+        handle->incStrong((void*)android_server_InputWindowHandle_getHandle);
         env->SetIntField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
                 reinterpret_cast<int>(handle));
     }
@@ -201,7 +201,7 @@
         env->SetIntField(obj, gInputWindowHandleClassInfo.ptr, 0);
 
         NativeInputWindowHandle* handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
-        handle->decStrong(obj);
+        handle->decStrong((void*)android_server_InputWindowHandle_getHandle);
     }
 }
 
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 036fc43..98de12a 100644
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -43,6 +43,12 @@
 static jmethodID method_requestRefLocation;
 static jmethodID method_requestSetID;
 static jmethodID method_requestUtcTime;
+static jmethodID method_reportGeofenceTransition;
+static jmethodID method_reportGeofenceStatus;
+static jmethodID method_reportGeofenceAddStatus;
+static jmethodID method_reportGeofenceRemoveStatus;
+static jmethodID method_reportGeofencePauseStatus;
+static jmethodID method_reportGeofenceResumeStatus;
 
 static const GpsInterface* sGpsInterface = NULL;
 static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -50,6 +56,7 @@
 static const GpsNiInterface* sGpsNiInterface = NULL;
 static const GpsDebugInterface* sGpsDebugInterface = NULL;
 static const AGpsRilInterface* sAGpsRilInterface = NULL;
+static const GpsGeofencingInterface* sGpsGeofencingInterface = NULL;
 
 // temporary storage for GPS callbacks
 static GpsSvStatus  sGpsSvStatus;
@@ -107,7 +114,7 @@
 
 static void set_capabilities_callback(uint32_t capabilities)
 {
-    ALOGD("set_capabilities_callback: %ld\n", capabilities);
+    ALOGD("set_capabilities_callback: %du\n", capabilities);
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -233,6 +240,97 @@
     create_thread_callback,
 };
 
+static void gps_geofence_transition_callback(int32_t geofence_id,  GpsLocation* location,
+        int32_t transition, GpsUtcTime timestamp)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceTransition, geofence_id,
+            location->flags, (jdouble)location->latitude, (jdouble)location->longitude,
+            (jdouble)location->altitude,
+            (jfloat)location->speed, (jfloat)location->bearing,
+            (jfloat)location->accuracy, (jlong)location->timestamp,
+            transition, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_status_callback(int32_t status, GpsLocation* location)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jint flags = 0;
+    jdouble latitude = 0;
+    jdouble longitude = 0;
+    jdouble altitude = 0;
+    jfloat speed = 0;
+    jfloat bearing = 0;
+    jfloat accuracy = 0;
+    jlong timestamp = 0;
+    if (location != NULL) {
+        flags = location->flags;
+        latitude = location->latitude;
+        longitude = location->longitude;
+        altitude = location->altitude;
+        speed = location->speed;
+        bearing = location->bearing;
+        accuracy = location->accuracy;
+        timestamp = location->timestamp;
+    }
+
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceStatus, status,
+            flags, latitude, longitude, altitude, speed, bearing, accuracy, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_add_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_add_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceAddStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_remove_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_remove_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceRemoveStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_resume_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_resume_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofenceResumeStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+static void gps_geofence_pause_callback(int32_t geofence_id, int32_t status)
+{
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (status != GPS_GEOFENCE_OPERATION_SUCCESS) {
+        ALOGE("Error in geofence_pause_callback: %d\n", status);
+    }
+    env->CallVoidMethod(mCallbacksObj, method_reportGeofencePauseStatus, geofence_id, status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+};
+
+GpsGeofenceCallbacks sGpsGeofenceCallbacks = {
+    gps_geofence_transition_callback,
+    gps_geofence_status_callback,
+    gps_geofence_add_callback,
+    gps_geofence_remove_callback,
+    gps_geofence_pause_callback,
+    gps_geofence_resume_callback,
+    create_thread_callback,
+};
+
 static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     int err;
     hw_module_t* module;
@@ -249,6 +347,18 @@
     method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
     method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
     method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
+    method_reportGeofenceTransition = env->GetMethodID(clazz,"reportGeofenceTransition",
+            "(IIDDDFFFJIJ)V");
+    method_reportGeofenceStatus = env->GetMethodID(clazz,"reportGeofenceStatus",
+            "(IIDDDFFFJ)V");
+    method_reportGeofenceAddStatus = env->GetMethodID(clazz,"reportGeofenceAddStatus",
+            "(II)V");
+    method_reportGeofenceRemoveStatus = env->GetMethodID(clazz,"reportGeofenceRemoveStatus",
+            "(II)V");
+    method_reportGeofenceResumeStatus = env->GetMethodID(clazz,"reportGeofenceResumeStatus",
+            "(II)V");
+    method_reportGeofencePauseStatus = env->GetMethodID(clazz,"reportGeofencePauseStatus",
+            "(II)V");
 
     err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
     if (err == 0) {
@@ -270,6 +380,8 @@
             (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
         sAGpsRilInterface =
             (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
+        sGpsGeofencingInterface =
+            (const GpsGeofencingInterface*)sGpsInterface->get_extension(GPS_GEOFENCING_INTERFACE);
     }
 }
 
@@ -287,7 +399,7 @@
     if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
         return false;
 
-    // if XTRA initialization fails we will disable it by sGpsXtraInterface to null,
+    // if XTRA initialization fails we will disable it by sGpsXtraInterface to NULL,
     // but continue to allow the rest of the GPS interface to work.
     if (sGpsXtraInterface && sGpsXtraInterface->init(&sGpsXtraCallbacks) != 0)
         sGpsXtraInterface = NULL;
@@ -297,6 +409,8 @@
         sGpsNiInterface->init(&sGpsNiCallbacks);
     if (sAGpsRilInterface)
         sAGpsRilInterface->init(&sAGpsRilCallbacks);
+    if (sGpsGeofencingInterface)
+        sGpsGeofencingInterface->init(&sGpsGeofenceCallbacks);
 
     return true;
 }
@@ -565,6 +679,62 @@
     }
 }
 
+static jboolean android_location_GpsLocationProvider_is_geofence_supported(JNIEnv* env,
+          jobject obj) {
+    if (sGpsGeofencingInterface != NULL) {
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_add_geofence(JNIEnv* env, jobject obj,
+        jint geofence_id, jdouble latitude, jdouble longitude, jdouble radius,
+        jint last_transition, jint monitor_transition, jint notification_responsiveness,
+        jint unknown_timer) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->add_geofence_area(geofence_id, latitude, longitude,
+                radius, last_transition, monitor_transition, notification_responsiveness,
+                unknown_timer);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_remove_geofence(JNIEnv* env, jobject obj,
+        jint geofence_id) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->remove_geofence_area(geofence_id);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_pause_geofence(JNIEnv* env, jobject obj,
+        jint geofence_id) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->pause_geofence(geofence_id);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
+static jboolean android_location_GpsLocationProvider_resume_geofence(JNIEnv* env, jobject obj,
+        jint geofence_id, jint monitor_transition) {
+    if (sGpsGeofencingInterface != NULL) {
+        sGpsGeofencingInterface->resume_geofence(geofence_id, monitor_transition);
+        return JNI_TRUE;
+    } else {
+        ALOGE("Geofence interface not available");
+    }
+    return JNI_FALSE;
+}
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
@@ -591,6 +761,11 @@
     {"native_agps_ni_message", "([BI)V", (void *)android_location_GpsLocationProvider_agps_send_ni_message},
     {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
     {"native_update_network_state", "(ZIZZLjava/lang/String;Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_update_network_state },
+    {"native_is_geofence_supported", "()Z", (void*) android_location_GpsLocationProvider_is_geofence_supported},
+    {"native_add_geofence", "(IDDDIIII)Z", (void *)android_location_GpsLocationProvider_add_geofence},
+    {"native_remove_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_remove_geofence},
+    {"native_pause_geofence", "(I)Z", (void *)android_location_GpsLocationProvider_pause_geofence},
+    {"native_resume_geofence", "(II)Z", (void *)android_location_GpsLocationProvider_resume_geofence}
 };
 
 int register_android_server_location_GpsLocationProvider(JNIEnv* env)
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 4ae013b..f955f4f 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -62,13 +62,17 @@
     private static final String MOBILE_IFACE = "rmnet3";
     private static final String WIFI_IFACE = "wlan6";
 
-    private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"));
-    private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"));
+    private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"),
+                                                                             MOBILE_IFACE);
+    private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"),
+                                                                             MOBILE_IFACE);
 
-    private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(
-            parse("192.168.0.66"), parse("192.168.0.1"));
-    private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(
-            parse("fd00::66"), parse("fd00::"));
+    private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(parse("192.168.0.66"),
+                                                                           parse("192.168.0.1"),
+                                                                           WIFI_IFACE);
+    private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::66"),
+                                                                           parse("fd00::"),
+                                                                           WIFI_IFACE);
 
     private INetworkManagementService mNetManager;
     private INetworkStatsService mStatsService;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 00c3a67..8ae3824 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -75,12 +75,12 @@
         Account a12 = new Account("account1", "type2");
         Account a22 = new Account("account2", "type2");
         Account a32 = new Account("account3", "type2");
-        mAms.addAccount(a11, "p11", null);
-        mAms.addAccount(a12, "p12", null);
-        mAms.addAccount(a21, "p21", null);
-        mAms.addAccount(a22, "p22", null);
-        mAms.addAccount(a31, "p31", null);
-        mAms.addAccount(a32, "p32", null);
+        mAms.addAccountExplicitly(a11, "p11", null);
+        mAms.addAccountExplicitly(a12, "p12", null);
+        mAms.addAccountExplicitly(a21, "p21", null);
+        mAms.addAccountExplicitly(a22, "p22", null);
+        mAms.addAccountExplicitly(a31, "p31", null);
+        mAms.addAccountExplicitly(a32, "p32", null);
 
         Account[] accounts = mAms.getAccounts(null);
         Arrays.sort(accounts, new AccountSorter());
@@ -111,8 +111,8 @@
     public void testPasswords() throws Exception {
         Account a11 = new Account("account1", "type1");
         Account a12 = new Account("account1", "type2");
-        mAms.addAccount(a11, "p11", null);
-        mAms.addAccount(a12, "p12", null);
+        mAms.addAccountExplicitly(a11, "p11", null);
+        mAms.addAccountExplicitly(a12, "p12", null);
 
         assertEquals("p11", mAms.getPassword(a11));
         assertEquals("p12", mAms.getPassword(a12));
@@ -134,8 +134,8 @@
         u12.putString("a", "a_a12");
         u12.putString("b", "b_a12");
         u12.putString("c", "c_a12");
-        mAms.addAccount(a11, "p11", u11);
-        mAms.addAccount(a12, "p12", u12);
+        mAms.addAccountExplicitly(a11, "p11", u11);
+        mAms.addAccountExplicitly(a12, "p12", u12);
 
         assertEquals("a_a11", mAms.getUserData(a11, "a"));
         assertEquals("b_a11", mAms.getUserData(a11, "b"));
@@ -158,8 +158,8 @@
     public void testAuthtokens() throws Exception {
         Account a11 = new Account("account1", "type1");
         Account a12 = new Account("account1", "type2");
-        mAms.addAccount(a11, "p11", null);
-        mAms.addAccount(a12, "p12", null);
+        mAms.addAccountExplicitly(a11, "p11", null);
+        mAms.addAccountExplicitly(a12, "p12", null);
 
         mAms.setAuthToken(a11, "att1", "a11_att1");
         mAms.setAuthToken(a11, "att2", "a11_att2");
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 1ab5f45..a70ebf4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -111,9 +111,9 @@
 
     private void writePackagesList() {
         writeFile(new File(getContext().getFilesDir(), "system/packages.list"),
-                ( "com.google.app1 11000 0 /data/data/com.google.app1"
-                + "com.google.app2 11001 0 /data/data/com.google.app2"
-                + "com.android.app3 11030 0 /data/data/com.android.app3")
+                ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1"
+                + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2"
+                + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3")
                 .getBytes());
     }
 
@@ -176,8 +176,8 @@
 
         // Enable/Disable a package
         PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
-        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0);
-        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1);
+        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
+        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
         assertEquals(COMPONENT_ENABLED_STATE_DISABLED, ps.getEnabled(0));
         assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1));
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 7ef1485..2e309be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -66,8 +66,8 @@
                     && !user.isPrimary()) {
                 found = true;
                 Bundle restrictions = mUserManager.getUserRestrictions(user.getUserHandle());
-                assertTrue("New user should have ALLOW_CONFIG_WIFI =true by default",
-                        restrictions.getBoolean(UserManager.ALLOW_CONFIG_WIFI));
+                assertFalse("New user should have DISALLOW_CONFIG_WIFI =false by default",
+                        restrictions.getBoolean(UserManager.DISALLOW_CONFIG_WIFI));
             }
         }
         assertTrue(found);
@@ -147,13 +147,13 @@
         List<UserInfo> users = mUserManager.getUsers();
         if (users.size() > 1) {
             Bundle restrictions = new Bundle();
-            restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, false);
-            restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
+            restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
+            restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false);
             mUserManager.setUserRestrictions(restrictions, new UserHandle(users.get(1).id));
             Bundle stored = mUserManager.getUserRestrictions(new UserHandle(users.get(1).id));
-            assertEquals(stored.getBoolean(UserManager.ALLOW_CONFIG_WIFI), true);
-            assertEquals(stored.getBoolean(UserManager.ALLOW_UNINSTALL_APPS), true);
-            assertEquals(stored.getBoolean(UserManager.ALLOW_INSTALL_APPS), false);
+            assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
+            assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
+            assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
         }
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 6e2a70d..31e01c0 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -162,13 +162,13 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CdmaCellIdentitiy:");
-        sb.append(super.toString());
+        StringBuilder sb = new StringBuilder("CellIdentitiyCdma:{");
         sb.append(" mNetworkId="); sb.append(mNetworkId);
         sb.append(" mSystemId="); sb.append(mSystemId);
         sb.append(" mBasestationId="); sb.append(mBasestationId);
         sb.append(" mLongitude="); sb.append(mLongitude);
         sb.append(" mLatitude="); sb.append(mLatitude);
+        sb.append("}");
 
         return sb.toString();
     }
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index bda96be..98113e7 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -147,13 +147,13 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("GsmCellIdentitiy:");
-        sb.append(super.toString());
+        StringBuilder sb = new StringBuilder("CellIdentitiyGsm:{");
         sb.append(" mMcc=").append(mMcc);
-        sb.append(" mMnc=").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();
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index f72d583..86924bd 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -142,13 +142,13 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("LteCellIdentitiy:");
-        sb.append(super.toString());
+        StringBuilder sb = new StringBuilder("CellIdentitiyLte:{");
         sb.append(" mMcc="); sb.append(mMcc);
         sb.append(" mMnc="); sb.append(mMnc);
         sb.append(" mCi="); sb.append(mCi);
         sb.append(" mPci="); sb.append(mPci);
         sb.append(" mTac="); sb.append(mTac);
+        sb.append("}");
 
         return sb.toString();
     }
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index f367f99..fe3c68b 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -149,7 +149,7 @@
         StringBuffer sb = new StringBuffer();
         String timeStampType;
 
-        sb.append(" mRegistered=").append(mRegistered ? "YES" : "NO");
+        sb.append("mRegistered=").append(mRegistered ? "YES" : "NO");
         timeStampType = timeStampTypeToString(mTimeStampType);
         sb.append(" mTimeStampType=").append(timeStampType);
         sb.append(" mTimeStamp=").append(mTimeStamp).append("ns");
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index a5d6e9c..6f2f1f6 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -87,10 +87,11 @@
     public String toString() {
         StringBuffer sb = new StringBuffer();
 
-        sb.append("CellInfoCdma:");
+        sb.append("CellInfoCdma:{");
         sb.append(super.toString());
-        sb.append(", ").append(mCellIdentityCdma);
-        sb.append(", ").append(mCellSignalStrengthCdma);
+        sb.append(" ").append(mCellIdentityCdma);
+        sb.append(" ").append(mCellSignalStrengthCdma);
+        sb.append("}");
 
         return sb.toString();
     }
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index bf0eca8..1bedddb 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -87,10 +87,11 @@
     public String toString() {
         StringBuffer sb = new StringBuffer();
 
-        sb.append("CellInfoGsm:");
+        sb.append("CellInfoGsm:{");
         sb.append(super.toString());
-        sb.append(", ").append(mCellIdentityGsm);
-        sb.append(", ").append(mCellSignalStrengthGsm);
+        sb.append(" ").append(mCellIdentityGsm);
+        sb.append(" ").append(mCellSignalStrengthGsm);
+        sb.append("}");
 
         return sb.toString();
     }
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index d7a58b6..287c9f0 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -91,10 +91,11 @@
     public String toString() {
         StringBuffer sb = new StringBuffer();
 
-        sb.append("CellInfoLte:");
+        sb.append("CellInfoLte:{");
         sb.append(super.toString());
-        sb.append(", ").append(mCellIdentityLte);
-        sb.append(", ").append(mCellSignalStrengthLte);
+        sb.append(" ").append(mCellIdentityLte);
+        sb.append(" ").append(mCellSignalStrengthLte);
+        sb.append("}");
 
         return sb.toString();
     }
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 3ed9cef..674955c 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -274,6 +274,33 @@
     }
 
     /**
+     * Make a SignalStrength object from the given parcel as passed up by
+     * the ril which does not have isGsm. isGsm will be changed by ServiceStateTracker
+     * so the default is a don't care.
+     *
+     * @hide
+     */
+    public static SignalStrength makeSignalStrengthFromRilParcel(Parcel in) {
+        if (DBG) log("Size of signalstrength parcel:" + in.dataSize());
+
+        SignalStrength ss = new SignalStrength();
+        ss.mGsmSignalStrength = in.readInt();
+        ss.mGsmBitErrorRate = in.readInt();
+        ss.mCdmaDbm = in.readInt();
+        ss.mCdmaEcio = in.readInt();
+        ss.mEvdoDbm = in.readInt();
+        ss.mEvdoEcio = in.readInt();
+        ss.mEvdoSnr = in.readInt();
+        ss.mLteSignalStrength = in.readInt();
+        ss.mLteRsrp = in.readInt();
+        ss.mLteRsrq = in.readInt();
+        ss.mLteRssnr = in.readInt();
+        ss.mLteCqi = in.readInt();
+
+        return ss;
+    }
+
+    /**
      * {@link Parcelable#writeToParcel}
      */
     public void writeToParcel(Parcel out, int flags) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8c47332..6400e68 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -907,6 +907,24 @@
     }
 
     /**
+     * Returns the Group Identifier Level1 for a GSM phone.
+     * Return null if it is unavailable.
+     * <p>
+     * Requires Permission:
+     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     */
+    public String getGroupIdLevel1() {
+        try {
+            return getSubscriberInfo().getGroupIdLevel1();
+        } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
+        }
+    }
+
+    /**
      * Returns the phone number string for line 1, for example, the MSISDN
      * for a GSM phone. Return null if it is unavailable.
      * <p>
@@ -1323,7 +1341,8 @@
     }
 
     /**
-     * Returns all observed cell information of the device.
+     * Returns all observed cell information of the device. This does
+     * not cause or change the rate of PhoneStateListner#onCellInfoChanged.
      *
      * @return List of CellInfo or null if info unavailable.
      *
@@ -1339,4 +1358,24 @@
             return null;
         }
     }
+
+    /**
+     * Sets the minimum time in milli-seconds between {@link PhoneStateListener#onCellInfoChanged
+     * PhoneStateListener.onCellInfoChanged} will be invoked.
+     *
+     * The default, 0, means invoke onCellInfoChanged when any of the reported
+     * information changes. Setting the value to INT_MAX(0x7fffffff) means never issue
+     * A onCellInfoChanged.
+     *
+     * @param rateInMillis the rate
+     *
+     * @hide
+     */
+    public void setCellInfoListRate(int rateInMillis) {
+        try {
+            getITelephony().setCellInfoListRate(rateInMillis);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 80c985f..9d556c0 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -30,10 +30,11 @@
      * DISCONNECTING: Connection.disconnect() has been called, but PDP
      *                context is not yet deactivated
      * FAILED: data connection fail for all apns settings
+     * RETRYING: data connection failed but we're going to retry.
      *
      * getDataConnectionState() maps State to DataState
      *      FAILED or IDLE : DISCONNECTED
-     *      CONNECTING or SCANNING: CONNECTING
+     *      RETRYING or CONNECTING or SCANNING: CONNECTING
      *      CONNECTED : CONNECTED or DISCONNECTING
      */
     public enum State {
@@ -42,7 +43,8 @@
         SCANNING,
         CONNECTED,
         DISCONNECTING,
-        FAILED
+        FAILED,
+        RETRYING
     }
 
     public enum Activity {
@@ -89,6 +91,8 @@
     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
     public static final int EVENT_ICC_CHANGED = BASE + 33;
+    public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34;
+    public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35;
 
     /***** Constants *****/
 
@@ -107,7 +111,4 @@
     public static final int ENABLED = 1;
 
     public static final String APN_TYPE_KEY = "apnType";
-    public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER =
-        "com.android.internal.telephony";
-    public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
 }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index da0326c..03940dc 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -39,6 +39,11 @@
     String getSubscriberId();
 
     /**
+     * Retrieves the Group Identifier Level1 for GSM phones.
+     */
+    String getGroupIdLevel1();
+
+    /**
      * Retrieves the serial number of the ICC, if applicable.
      */
     String getIccSerialNumber();
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1449ab1..b78f589 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -294,5 +294,10 @@
      * Returns the all observed cell information of the device.
      */
     List<CellInfo> getAllCellInfo();
+
+    /**
+     * Sets minimum time in milli-seconds between onCellInfoChanged
+     */
+    void setCellInfoListRate(int rateInMillis);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 077ad68..9650b99 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -260,6 +260,8 @@
     int RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU = 106;
     int RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS = 107;
     int RIL_REQUEST_VOICE_RADIO_TECH = 108;
+    int RIL_REQUEST_GET_CELL_INFO_LIST = 109;
+    int RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE = 110;
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
@@ -297,4 +299,5 @@
     int RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE = 1033;
     int RIL_UNSOL_RIL_CONNECTED = 1034;
     int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035;
+    int RIL_UNSOL_CELL_INFO_LIST = 1036;
 }
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index fbdd333..62f6aff 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -15,6 +15,8 @@
  */
 package com.android.tests.applaunch;
 
+import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.app.ActivityManager;
 import android.app.ActivityManager.ProcessErrorStateInfo;
 import android.app.ActivityManagerNative;
@@ -32,9 +34,12 @@
 import android.test.InstrumentationTestRunner;
 import android.util.Log;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * This test is intended to measure the time it takes for the apps to start.
@@ -48,16 +53,26 @@
 public class AppLaunch extends InstrumentationTestCase {
 
     private static final int JOIN_TIMEOUT = 10000;
-    private static final String TAG = "AppLaunch";
+    private static final String TAG = AppLaunch.class.getSimpleName();
     private static final String KEY_APPS = "apps";
+    private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
+    // optional parameter: comma separated list of required account types before proceeding
+    // with the app launch
+    private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
+    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle
+    private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
+    private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps
 
     private Map<String, Intent> mNameToIntent;
     private Map<String, String> mNameToProcess;
     private Map<String, String> mNameToResultKey;
-
+    private Map<String, Long> mNameToLaunchTime;
     private IActivityManager mAm;
+    private int mLaunchIterations = 10;
+    private Bundle mResult = new Bundle();
+    private Set<String> mRequiredAccounts;
 
-    public void testMeasureStartUpTime() throws RemoteException {
+    public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException {
         InstrumentationTestRunner instrumentation =
                 (InstrumentationTestRunner)getInstrumentation();
         Bundle args = instrumentation.getArguments();
@@ -65,26 +80,61 @@
 
         createMappings();
         parseArgs(args);
+        checkAccountSignIn();
 
-        Bundle results = new Bundle();
+        // do initial app launch, without force stopping
         for (String app : mNameToResultKey.keySet()) {
-            try {
-                startApp(app, results);
-                sleep(750);
-                closeApp(app);
-                sleep(2000);
-            } catch (NameNotFoundException e) {
-                Log.i(TAG, "Application " + app + " not found");
+            long launchTime = startApp(app, false);
+            if (launchTime <=0 ) {
+                mNameToLaunchTime.put(app, -1L);
+                // simply pass the app if launch isn't successful
+                // error should have already been logged by startApp
+                continue;
             }
-
+            sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
+            closeApp(app, false);
+            sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
         }
-        instrumentation.sendStatus(0, results);
+        // do the real app launch now
+        for (int i = 0; i < mLaunchIterations; i++) {
+            for (String app : mNameToResultKey.keySet()) {
+                long totalLaunchTime = mNameToLaunchTime.get(app);
+                long launchTime = 0;
+                if (totalLaunchTime < 0) {
+                    // skip if the app has previous failures
+                    continue;
+                }
+                launchTime = startApp(app, true);
+                if (launchTime <= 0) {
+                    // if it fails once, skip the rest of the launches
+                    mNameToLaunchTime.put(app, -1L);
+                    continue;
+                }
+                totalLaunchTime += launchTime;
+                mNameToLaunchTime.put(app, totalLaunchTime);
+                sleep(POST_LAUNCH_IDLE_TIMEOUT);
+                closeApp(app, true);
+                sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
+            }
+        }
+        for (String app : mNameToResultKey.keySet()) {
+            long totalLaunchTime = mNameToLaunchTime.get(app);
+            if (totalLaunchTime != -1) {
+                mResult.putDouble(mNameToResultKey.get(app),
+                        ((double) totalLaunchTime) / mLaunchIterations);
+            }
+        }
+        instrumentation.sendStatus(0, mResult);
     }
 
     private void parseArgs(Bundle args) {
         mNameToResultKey = new LinkedHashMap<String, String>();
+        mNameToLaunchTime = new HashMap<String, Long>();
+        String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
+        if (launchIterations != null) {
+            mLaunchIterations = Integer.parseInt(launchIterations);
+        }
         String appList = args.getString(KEY_APPS);
-
         if (appList == null)
             return;
 
@@ -97,6 +147,14 @@
             }
 
             mNameToResultKey.put(parts[0], parts[1]);
+            mNameToLaunchTime.put(parts[0], 0L);
+        }
+        String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
+        if (requiredAccounts != null) {
+            mRequiredAccounts = new HashSet<String>();
+            for (String accountType : requiredAccounts.split(",")) {
+                mRequiredAccounts.add(accountType);
+            }
         }
     }
 
@@ -118,23 +176,26 @@
                         | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
                 startIntent.setClassName(ri.activityInfo.packageName,
                         ri.activityInfo.name);
-                mNameToIntent.put(ri.loadLabel(pm).toString(), startIntent);
-                mNameToProcess.put(ri.loadLabel(pm).toString(),
-                        ri.activityInfo.processName);
+                String appName = ri.loadLabel(pm).toString();
+                if (appName != null) {
+                    mNameToIntent.put(appName, startIntent);
+                    mNameToProcess.put(appName, ri.activityInfo.processName);
+                }
             }
         }
     }
 
-    private void startApp(String appName, Bundle results)
+    private long startApp(String appName, boolean forceStopBeforeLaunch)
             throws NameNotFoundException, RemoteException {
         Log.i(TAG, "Starting " + appName);
 
         Intent startIntent = mNameToIntent.get(appName);
         if (startIntent == null) {
             Log.w(TAG, "App does not exist: " + appName);
-            return;
+            mResult.putString(mNameToResultKey.get(appName), "App does not exist");
+            return -1;
         }
-        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent);
+        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch);
         Thread t = new Thread(runnable);
         t.start();
         try {
@@ -143,27 +204,69 @@
             // ignore
         }
         WaitResult result = runnable.getResult();
-        if(t.isAlive() || (result != null && result.result != ActivityManager.START_SUCCESS)) {
+        // report error if any of the following is true:
+        // * launch thread is alive
+        // * result is not null, but:
+        //   * result is not START_SUCESS
+        //   * or in case of no force stop, result is not TASK_TO_FRONT either
+        if (t.isAlive() || (result != null
+                && ((result.result != ActivityManager.START_SUCCESS)
+                        && (!forceStopBeforeLaunch
+                                && result.result != ActivityManager.START_TASK_TO_FRONT)))) {
             Log.w(TAG, "Assuming app " + appName + " crashed.");
-            reportError(appName, mNameToProcess.get(appName), results);
-            return;
+            reportError(appName, mNameToProcess.get(appName));
+            return -1;
         }
-        results.putString(mNameToResultKey.get(appName), String.valueOf(result.thisTime));
+        return result.thisTime;
     }
 
-    private void closeApp(String appName) {
+    private void checkAccountSignIn() {
+        // ensure that the device has the required account types before starting test
+        // e.g. device must have a valid Google account sign in to measure a meaningful launch time
+        // for Gmail
+        if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
+            return;
+        }
+        final AccountManager am =
+                (AccountManager) getInstrumentation().getTargetContext().getSystemService(
+                        Context.ACCOUNT_SERVICE);
+        Account[] accounts = am.getAccounts();
+        // use set here in case device has multiple accounts of the same type
+        Set<String> foundAccounts = new HashSet<String>();
+        for (Account account : accounts) {
+            if (mRequiredAccounts.contains(account.type)) {
+                foundAccounts.add(account.type);
+            }
+        }
+        // check if account type matches, if not, fail test with message on what account types
+        // are missing
+        if (mRequiredAccounts.size() != foundAccounts.size()) {
+            mRequiredAccounts.removeAll(foundAccounts);
+            StringBuilder sb = new StringBuilder("Device missing these accounts:");
+            for (String account : mRequiredAccounts) {
+                sb.append(' ');
+                sb.append(account);
+            }
+            fail(sb.toString());
+        }
+    }
+
+    private void closeApp(String appName, boolean forceStopApp) {
         Intent homeIntent = new Intent(Intent.ACTION_MAIN);
         homeIntent.addCategory(Intent.CATEGORY_HOME);
         homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         getInstrumentation().getContext().startActivity(homeIntent);
-        Intent startIntent = mNameToIntent.get(appName);
-        if (startIntent != null) {
-            String packageName = startIntent.getComponent().getPackageName();
-            try {
-                mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error closing app", e);
+        sleep(POST_LAUNCH_IDLE_TIMEOUT);
+        if (forceStopApp) {
+            Intent startIntent = mNameToIntent.get(appName);
+            if (startIntent != null) {
+                String packageName = startIntent.getComponent().getPackageName();
+                try {
+                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error closing app", e);
+                }
             }
         }
     }
@@ -176,7 +279,7 @@
         }
     }
 
-    private void reportError(String appName, String processName, Bundle results) {
+    private void reportError(String appName, String processName) {
         ActivityManager am = (ActivityManager) getInstrumentation()
                 .getContext().getSystemService(Context.ACTIVITY_SERVICE);
         List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
@@ -186,12 +289,12 @@
                     continue;
 
                 Log.w(TAG, appName + " crashed: " + crash.shortMsg);
-                results.putString(mNameToResultKey.get(appName), crash.shortMsg);
+                mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
                 return;
             }
         }
 
-        results.putString(mNameToResultKey.get(appName),
+        mResult.putString(mNameToResultKey.get(appName),
                 "Crashed for unknown reason");
         Log.w(TAG, appName
                 + " not found in process list, most likely it is crashed");
@@ -200,8 +303,11 @@
     private class AppLaunchRunnable implements Runnable {
         private Intent mLaunchIntent;
         private IActivityManager.WaitResult mResult;
-        public AppLaunchRunnable(Intent intent) {
+        private boolean mForceStopBeforeLaunch;
+
+        public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch) {
             mLaunchIntent = intent;
+            mForceStopBeforeLaunch = forceStopBeforeLaunch;
         }
 
         public IActivityManager.WaitResult getResult() {
@@ -211,7 +317,9 @@
         public void run() {
             try {
                 String packageName = mLaunchIntent.getComponent().getPackageName();
-                mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+                if (mForceStopBeforeLaunch) {
+                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+                }
                 String mimeType = mLaunchIntent.getType();
                 if (mimeType == null && mLaunchIntent.getData() != null
                         && "content".equals(mLaunchIntent.getData().getScheme())) {
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index 4d60c83..7ae0fb8 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -127,6 +127,10 @@
         homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         Intent intent = mPackageManager.getLaunchIntentForPackage(packageName);
+        // Skip if the apk does not have a launch intent.
+        if (intent == null) {
+            return null;
+        }
 
         // We check for any Crash or ANR dialogs that are already up, and we ignore them.  This is
         // so that we don't report crashes that were caused by prior apps (which those particular
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
index 02cb4b6..1847f43 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MoreShadersActivity.java
@@ -57,6 +57,7 @@
         private Paint mLargePaint;
         private BitmapShader mScaled2Shader;
         private ColorFilter mColorFilter;
+        private final Matrix mMtx1;
 
         ShadersView(Context c) {
             super(c);
@@ -70,7 +71,7 @@
             mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR,
                     Shader.TileMode.MIRROR);
             Matrix m2 = new Matrix();
-            m2.setScale(0.5f, 0.5f);
+            m2.setScale(0.1f, 0.1f);
             mScaledShader.setLocalMatrix(m2);
             
             mScaled2Shader = new BitmapShader(texture, Shader.TileMode.MIRROR,
@@ -81,12 +82,20 @@
 
             mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
                     Color.RED, 0x7f00ff00, Shader.TileMode.CLAMP);
-            
+            Matrix m4 = new Matrix();
+            m4.setScale(0.5f, 0.5f);
+            mHorGradient.setLocalMatrix(m4);
+
             mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
                     Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
 
             mComposeShader = new ComposeShader(mScaledShader, mHorGradient,
                     PorterDuff.Mode.SRC_OVER);
+            mMtx1 = new Matrix();
+            mMtx1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
+            mMtx1.postRotate(45, 0, 0);
+            mComposeShader.setLocalMatrix(mMtx1);
+
             mCompose2Shader = new ComposeShader(mHorGradient, mScaledShader,
                     PorterDuff.Mode.SRC_OUT);
 
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
index 9ab2a86..9f97311 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
@@ -33,6 +33,7 @@
     private Path mPath;
 
     private final Random mRandom = new Random();
+    @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
     private final ArrayList<Path> mPathList = new ArrayList<Path>();
 
     @Override
@@ -45,19 +46,32 @@
         setContentView(view);
     }
 
-    private Path makePath() {
+    private static Path makePath() {
         Path path = new Path();
         buildPath(path);
         return path;
     }
 
-    private void buildPath(Path path) {
+    private static void buildPath(Path path) {
         path.moveTo(0.0f, 0.0f);
         path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.0f);
         path.cubicTo(100.0f, 200.0f, 50.0f, 300.0f, -80.0f, 200.0f);
         path.cubicTo(-80.0f, 200.0f, 100.0f, 200.0f, 200.0f, 0.0f);
     }
 
+    private static Path makeLargePath() {
+        Path path = new Path();
+        buildLargePath(path);
+        return path;
+    }
+
+    private static void buildLargePath(Path path) {
+        path.moveTo(0.0f, 0.0f);
+        path.cubicTo(0.0f, 0.0f, 10000.0f, 15000.0f, 10000.0f, 20000.0f);
+        path.cubicTo(10000.0f, 20000.0f, 5000.0f, 30000.0f, -8000.0f, 20000.0f);
+        path.cubicTo(-8000.0f, 20000.0f, 10000.0f, 20000.0f, 20000.0f, 0.0f);
+    }
+
     public class PathsView extends View {
         private final Paint mMediumPaint;
 
@@ -97,6 +111,9 @@
                 int r = mRandom.nextInt(10);
                 if (r == 5 || r == 3) {
                     mPathList.add(path);
+                } else if (r == 7) {
+                    path = makeLargePath();
+                    mPathList.add(path);
                 }
     
                 canvas.save();
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
index 97e5526..61dca78 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ShapesActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Path;
 import android.graphics.RectF;
 import android.os.Bundle;
 import android.view.View;
@@ -34,12 +35,13 @@
     }
 
     static class ShapesView extends View {
-        private Paint mNormalPaint;
-        private Paint mStrokePaint;
-        private Paint mFillPaint;
-        private RectF mRect;
-        private RectF mOval;
-        private RectF mArc;
+        private final Paint mNormalPaint;
+        private final Paint mStrokePaint;
+        private final Paint mFillPaint;
+        private final RectF mRect;
+        private final RectF mOval;
+        private final RectF mArc;
+        private final Path mTriangle;
 
         ShapesView(Context c) {
             super(c);
@@ -65,6 +67,12 @@
 
             mOval = new RectF(0.0f, 0.0f, 80.0f, 45.0f);
             mArc = new RectF(0.0f, 0.0f, 100.0f, 120.0f);
+
+            mTriangle = new Path();
+            mTriangle.moveTo(0.0f, 90.0f);
+            mTriangle.lineTo(45.0f, 0.0f);
+            mTriangle.lineTo(90.0f, 90.0f);
+            mTriangle.close();
         }
 
         @Override
@@ -136,6 +144,17 @@
             canvas.translate(0.0f, 110.0f);
             canvas.drawArc(mArc, 30.0f, 100.0f, false, mFillPaint);
             canvas.restore();
+
+            canvas.save();
+            canvas.translate(50.0f, 400.0f);
+            canvas.drawPath(mTriangle, mNormalPaint);
+
+            canvas.translate(110.0f, 0.0f);
+            canvas.drawPath(mTriangle, mStrokePaint);
+
+            canvas.translate(110.0f, 0.0f);
+            canvas.drawPath(mTriangle, mFillPaint);
+            canvas.restore();
         }
     }
 }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
index 854a3f4..dbaedf9 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
@@ -47,7 +47,7 @@
         {
             public void onClick (View v)
             {
-                InputMethodManager imm = InputMethodManager.getInstance(instance);
+                InputMethodManager imm = InputMethodManager.getInstance();
                 if (mKeyboardIsActive)
                 {
                     imm.hideSoftInputFromInputMethod(v.getWindowToken(), 0);
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
index bc77e04..32f80a3 100644
--- a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
@@ -66,7 +66,7 @@
         mExpectAutoPop = (keyboardType  == Configuration.KEYBOARD_NOKEYS ||
                 keyboardType == Configuration.KEYBOARD_UNDEFINED);
 
-        mImm = InputMethodManager.getInstance(mTargetActivity);
+        mImm = InputMethodManager.getInstance();
 
         KeyguardManager keyguardManager =
             (KeyguardManager) getInstrumentation().getContext().getSystemService(
diff --git a/tests/RenderScriptTests/Balls/Android.mk b/tests/RenderScriptTests/Balls/Android.mk
deleted file mode 100644
index 77281ce..0000000
--- a/tests/RenderScriptTests/Balls/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsBalls
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Balls/AndroidManifest.xml b/tests/RenderScriptTests/Balls/AndroidManifest.xml
deleted file mode 100644
index 80e6b39..0000000
--- a/tests/RenderScriptTests/Balls/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.balls">
-    <uses-sdk android:minSdkVersion="14" />
-    <application 
-        android:label="RsBalls"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="Balls"
-                  android:screenOrientation="landscape">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/Balls/_index.html b/tests/RenderScriptTests/Balls/_index.html
deleted file mode 100644
index 8760485..0000000
--- a/tests/RenderScriptTests/Balls/_index.html
+++ /dev/null
@@ -1 +0,0 @@
-<p>A brute force physics simulation that renders many balls onto the screen and moves them according to user touch and gravity.</p>
\ No newline at end of file
diff --git a/tests/RenderScriptTests/Balls/res/drawable/flares.png b/tests/RenderScriptTests/Balls/res/drawable/flares.png
deleted file mode 100644
index 3a5c970..0000000
--- a/tests/RenderScriptTests/Balls/res/drawable/flares.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png b/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/Balls/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java
deleted file mode 100644
index 2c6558e..0000000
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/Balls.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2008 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.example.android.rs.balls;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-
-public class Balls extends Activity implements SensorEventListener {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private BallsView mView;
-    private SensorManager mSensorManager;
-
-    // get the current looper (from your Activity UI thread for instance
-
-
-    public void onSensorChanged(SensorEvent event) {
-        //android.util.Log.d("rs", "sensor: " + event.sensor + ", x: " + event.values[0] + ", y: " + event.values[1] + ", z: " + event.values[2]);
-        synchronized (this) {
-            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
-                if(mView != null) {
-                    mView.setAccel(event.values[0], event.values[1], event.values[2]);
-                }
-            }
-        }
-    }
-
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new BallsView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        mSensorManager.registerListener(this,
-                                        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
-                                        SensorManager.SENSOR_DELAY_FASTEST);
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mView.pause();
-        onStop();
-    }
-
-    @Override
-    protected void onStop() {
-        mSensorManager.unregisterListener(this);
-        super.onStop();
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
-
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java
deleted file mode 100644
index d9d182c..0000000
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsRS.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2008 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.example.android.rs.balls;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-
-public class BallsRS {
-    public static final int PART_COUNT = 4000;
-
-    public BallsRS() {
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private ScriptC_balls mScript;
-    private ScriptC_ball_physics mPhysicsScript;
-    private ProgramFragment mPFPoints;
-    private ScriptField_Point mPoints;
-    private ScriptField_VpConsts mVpConsts;
-    private ScriptField_BallGrid mGrid;
-    private ScriptField_Ball mBalls;
-    private Allocation mGridCache;
-
-    void updateProjectionMatrices() {
-        mVpConsts = new ScriptField_VpConsts(mRS, 1,
-                                             Allocation.USAGE_SCRIPT |
-                                             Allocation.USAGE_GRAPHICS_CONSTANTS);
-        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
-        Matrix4f mvp = new Matrix4f();
-        mvp.loadOrtho(0, mRS.getWidth(), mRS.getHeight(), 0, -1, 1);
-        i.MVP = mvp;
-        mVpConsts.set(i, 0, true);
-    }
-
-    private void createProgramVertex() {
-        updateProjectionMatrices();
-
-        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
-        String t =  "varying vec4 varColor;\n" +
-                    "void main() {\n" +
-                    "  vec4 pos = vec4(0.0, 0.0, 0.0, 1.0);\n" +
-                    "  pos.xy = ATTRIB_position;\n" +
-                    "  gl_Position = UNI_MVP * pos;\n" +
-                    "  varColor = ATTRIB_color;\n" +
-                    "  gl_PointSize = 12.0;\n" +
-                    "}\n";
-        sb.setShader(t);
-        sb.addConstant(mVpConsts.getType());
-        sb.addInput(mPoints.getElement());
-        ProgramVertex pvs = sb.create();
-        pvs.bindConstants(mVpConsts.getAllocation(), 0);
-        mRS.bindProgramVertex(pvs);
-    }
-
-    private Allocation loadTexture(int id) {
-        final Allocation allocation =
-            Allocation.createFromBitmapResource(mRS, mRes,
-                id, Allocation.MipmapControl.MIPMAP_NONE,
-                Allocation.USAGE_GRAPHICS_TEXTURE);
-        return allocation;
-    }
-
-    ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
-        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
-        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
-        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
-        builder.setDitherEnabled(false);
-        builder.setDepthMaskEnabled(false);
-        return builder.create();
-    }
-
-    private void createPF(int width, int height) {
-        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(mRS);
-        pfb.setPointSpriteTexCoordinateReplacement(true);
-        pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
-                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-        pfb.setVaryingColor(true);
-        mPFPoints = pfb.create();
-    }
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-
-        createPF(width, height);
-
-        mPFPoints.bindTexture(loadTexture(R.drawable.flares), 0);
-
-        mPoints = new ScriptField_Point(mRS, PART_COUNT, Allocation.USAGE_SCRIPT);
-
-        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
-        smb.addVertexAllocation(mPoints.getAllocation());
-        smb.addIndexSetType(Mesh.Primitive.POINT);
-        Mesh smP = smb.create();
-
-        mGrid = ScriptField_BallGrid.create2D(mRS, (width + 99) / 100, (height + 99) / 100);
-        mGridCache = Allocation.createSized(mRS, Element.F32_2(mRS), PART_COUNT);
-        mBalls = new ScriptField_Ball(mRS, PART_COUNT, Allocation.USAGE_SCRIPT);
-
-        mPhysicsScript = new ScriptC_ball_physics(mRS);
-        mPhysicsScript.set_gGridCache(mGridCache);
-        mPhysicsScript.set_gBalls(mBalls.getAllocation());
-
-        mScript = new ScriptC_balls(mRS);
-        mScript.set_partMesh(smP);
-        mScript.set_physics_script(mPhysicsScript);
-        mScript.bind_point(mPoints);
-        mScript.bind_balls(mBalls);
-        mScript.set_gGrid(mGrid.getAllocation());
-        mScript.bind_gGridCache(mGridCache);
-
-        mScript.set_gPFPoints(mPFPoints);
-        createProgramVertex();
-
-        mRS.bindProgramStore(BLEND_ADD_DEPTH_NONE(mRS));
-
-        mPhysicsScript.set_gMinPos(new Float2(5, 5));
-        mPhysicsScript.set_gMaxPos(new Float2(width - 5, height - 5));
-        mPhysicsScript.set_gGrid(mGrid.getAllocation());
-
-        mScript.invoke_initParts(width, height);
-
-        mRS.bindRootScript(mScript);
-    }
-
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-        mPhysicsScript.invoke_touch(x, y, pressure * mRS.getWidth() / 1280, id);
-    }
-
-    public void setAccel(float x, float y) {
-        mPhysicsScript.set_gGravityVector(new Float2(x, y));
-    }
-
-}
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
deleted file mode 100644
index 041782d..0000000
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2008 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.example.android.rs.balls;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class BallsView extends RSSurfaceView {
-
-    public BallsView(Context context) {
-        super(context);
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private BallsRS mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new BallsRS();
-            mRender.init(mRS, getResources(), w, h);
-        }
-        mRender.updateProjectionMatrices();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if(mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        int act = ev.getActionMasked();
-        if (act == ev.ACTION_UP) {
-            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
-            return false;
-        } else if (act == MotionEvent.ACTION_POINTER_UP) {
-            // only one pointer going up, we can get the index like this
-            int pointerIndex = ev.getActionIndex();
-            int pointerId = ev.getPointerId(pointerIndex);
-            mRender.newTouchPosition(0, 0, 0, pointerId);
-            return false;
-        }
-        int count = ev.getHistorySize();
-        int pcount = ev.getPointerCount();
-
-        for (int p=0; p < pcount; p++) {
-            int id = ev.getPointerId(p);
-            mRender.newTouchPosition(ev.getX(p),
-                                     ev.getY(p),
-                                     ev.getPressure(p),
-                                     id);
-
-            for (int i=0; i < count; i++) {
-                mRender.newTouchPosition(ev.getHistoricalX(p, i),
-                                         ev.getHistoricalY(p, i),
-                                         ev.getHistoricalPressure(p, i),
-                                         id);
-            }
-        }
-        return true;
-    }
-
-    void setAccel(float x, float y, float z) {
-        if ((mRender == null) || (mRS == null)) {
-            return;
-        }
-        mRender.setAccel(x, -y);
-    }
-
-}
-
-
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs
deleted file mode 100644
index 5b5d2e0..0000000
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/ball_physics.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.balls)
-
-#include "balls.rsh"
-
-float2 gGravityVector = {0.f, 9.8f};
-
-float2 gMinPos = {0.f, 0.f};
-float2 gMaxPos = {1280.f, 700.f};
-
-static float2 touchPos[10];
-static float touchPressure[10];
-static const float gDT = 1.f / 30.f;
-
-rs_allocation gGrid;
-rs_allocation gGridCache;
-rs_allocation gBalls;
-
-float gScale = 1.f;
-
-void touch(float x, float y, float pressure, int id) {
-    if (id >= 10) {
-        return;
-    }
-
-    touchPos[id].x = x;
-    touchPos[id].y = y;
-    touchPressure[id] = pressure;
-}
-
-void root(Ball_t *ball, uint32_t x) {
-    float2 fv = 0;
-    float pressure = 0;
-    float2 pos = ball->position;
-    int2 gridPos[9];
-
-    gridPos[0] = convert_int2((ball->position / 100.f) /*- 0.4999f*/);
-    gridPos[1] = (int2){gridPos[0].x - 1, gridPos[0].y - 1};
-    gridPos[2] = (int2){gridPos[0].x + 0, gridPos[0].y - 1};
-    gridPos[3] = (int2){gridPos[0].x + 1, gridPos[0].y - 1};
-    gridPos[4] = (int2){gridPos[0].x - 1, gridPos[0].y};
-    gridPos[5] = (int2){gridPos[0].x + 1, gridPos[0].y};
-    gridPos[6] = (int2){gridPos[0].x - 1, gridPos[0].y + 1};
-    gridPos[7] = (int2){gridPos[0].x + 0, gridPos[0].y + 1};
-    gridPos[8] = (int2){gridPos[0].x + 1, gridPos[0].y + 1};
-
-    for (int gct=0; gct < 9; gct++) {
-        if ((gridPos[gct].x >= rsAllocationGetDimX(gGrid)) ||
-            (gridPos[gct].x < 0) ||
-            (gridPos[gct].y >= rsAllocationGetDimY(gGrid)) ||
-            (gridPos[gct].y < 0)) {
-            continue;
-        }
-        //rsDebug("grid ", gridPos[gct]);
-        const BallGrid_t *bg = (const BallGrid_t *)rsGetElementAt(gGrid, gridPos[gct].x, gridPos[gct].y);
-
-        for (int cidx = 0; cidx < bg->count; cidx++) {
-            float2 bcptr = rsGetElementAt_float2(gGridCache, bg->cacheIdx + cidx);
-            float2 vec = bcptr - pos;
-            float2 vec2 = vec * vec;
-            float len2 = vec2.x + vec2.y;
-
-            if ((len2 < 10000.f) && (len2 > 0.f)) {
-                float t = native_powr(len2, 1.5f) + 16.0f;
-                float2 pfv = (vec / t) * 16000.f;
-                pressure += length(pfv);
-                fv -= pfv;
-            }
-        }
-    }
-
-    //fv /= ball->size * ball->size * ball->size;
-    fv -= gGravityVector * 4.f * gScale;
-    fv *= gDT;
-
-    for (int i=0; i < 10; i++) {
-        if (touchPressure[i] > 0.1f) {
-            float2 vec = touchPos[i] - ball->position;
-            float2 vec2 = vec * vec;
-            float len2 = max(2.f, vec2.x + vec2.y);
-            float2 pfv = (vec / len2) * touchPressure[i] * 500.f * gScale;
-            pressure += length(pfv);
-            fv -= pfv;
-        }
-    }
-
-    ball->delta = (ball->delta * (1.f - 0.008f)) + fv;
-    ball->position = ball->position + (ball->delta * gDT);
-
-    const float wallForce = 400.f * gScale;
-    if (ball->position.x > (gMaxPos.x - 20.f)) {
-        float d = gMaxPos.x - ball->position.x;
-        if (d < 0.f) {
-            if (ball->delta.x > 0) {
-                ball->delta.x *= -0.7f;
-            }
-            ball->position.x = gMaxPos.x - 1.f;
-        } else {
-            ball->delta.x -= min(wallForce / (d * d), 10.f);
-        }
-    }
-
-    if (ball->position.x < (gMinPos.x + 20.f)) {
-        float d = ball->position.x - gMinPos.x;
-        if (d < 0.f) {
-            if (ball->delta.x < 0) {
-                ball->delta.x *= -0.7f;
-            }
-            ball->position.x = gMinPos.x + 1.f;
-        } else {
-            ball->delta.x += min(wallForce / (d * d), 10.f);
-        }
-    }
-
-    if (ball->position.y > (gMaxPos.y - 20.f)) {
-        float d = gMaxPos.y - ball->position.y;
-        if (d < 0.f) {
-            if (ball->delta.y > 0) {
-                ball->delta.y *= -0.7f;
-            }
-            ball->position.y = gMaxPos.y - 1.f;
-        } else {
-            ball->delta.y -= min(wallForce / (d * d), 10.f);
-        }
-    }
-
-    if (ball->position.y < (gMinPos.y + 20.f)) {
-        float d = ball->position.y - gMinPos.y;
-        if (d < 0.f) {
-            if (ball->delta.y < 0) {
-                ball->delta.y *= -0.7f;
-            }
-            ball->position.y = gMinPos.y + 1.f;
-        } else {
-            ball->delta.y += min(wallForce / (d * d * d), 10.f);
-        }
-    }
-
-    // low pressure ~500, high ~2500
-    pressure = max(pressure - 400.f, 0.f);
-    ball->pressure = pressure;
-
-    //rsDebug("p ", pressure);
-
-    float4 color = 1.f;
-    color.r = pow(pressure, 0.25f) / 12.f;
-    color.b = 1.f - color.r;
-    color.g = sin(pressure / 1500.f * 3.14f);
-    color.rgb = max(color.rgb, (float3)0);
-    color.rgb = normalize(color.rgb);
-    ball->color = rsPackColorTo8888(color);
-
-    //rsDebug("physics pos out", ball->position);
-}
-
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs
deleted file mode 100644
index 9be9f38..0000000
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.balls)
-#include "rs_graphics.rsh"
-
-#include "balls.rsh"
-
-#pragma stateVertex(parent)
-#pragma stateStore(parent)
-
-rs_program_fragment gPFPoints;
-rs_mesh partMesh;
-
-rs_allocation gGrid;
-BallGrid_t *unused1;
-float2 *gGridCache;
-
-typedef struct __attribute__((packed, aligned(4))) Point {
-    float2 position;
-    uchar4 color;
-} Point_t;
-Point_t *point;
-
-typedef struct VpConsts {
-    rs_matrix4x4 MVP;
-} VpConsts_t;
-VpConsts_t *vpConstants;
-
-rs_script physics_script;
-
-
-void initParts(int w, int h)
-{
-    uint32_t dimX = rsAllocationGetDimX(rsGetAllocation(balls));
-
-    for (uint32_t ct=0; ct < dimX; ct++) {
-        balls[ct].position.x = rsRand(0.f, (float)w);
-        balls[ct].position.y = rsRand(0.f, (float)h);
-        balls[ct].delta.x = 0.f;
-        balls[ct].delta.y = 0.f;
-    }
-}
-
-int root() {
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-
-    int2 gridDims = (int2){ rsAllocationGetDimX(gGrid),
-                            rsAllocationGetDimY(gGrid) };
-
-    rs_allocation ain = rsGetAllocation(balls);
-    int32_t dimX = rsAllocationGetDimX(ain);
-
-    // Binning
-    // Clear the particle list
-    for (uint32_t ct=0; ct < dimX; ct++) {
-        balls[ct].next = -1;
-    }
-
-    // Clear the grid
-    for (uint32_t y=0; y < gridDims.y; y++) {
-        for (uint32_t x=0; x < gridDims.x; x++) {
-            BallGrid_t *bg = (BallGrid_t *)rsGetElementAt(gGrid, x, y);
-            bg->count = 0;
-            bg->idx = -1;
-        }
-    }
-
-    // Create the particle list per grid
-    for (uint32_t ct=0; ct < dimX; ct++) {
-        int2 p = convert_int2(balls[ct].position / 100.f);
-        p.x = rsClamp(p.x, 0, (int)(gridDims.x-1));
-        p.y = rsClamp(p.y, 0, (int)(gridDims.y-1));
-        BallGrid_t *bg = (BallGrid_t *)rsGetElementAt(gGrid, p.x, p.y);
-        bg->count ++;
-        balls[ct].next = bg->idx;
-        bg->idx = ct;
-    }
-
-    // Create the sorted grid cache
-    uint32_t gridIdx = 0;
-    for (uint32_t y=0; y < gridDims.y; y++) {
-        for (uint32_t x=0; x < gridDims.x; x++) {
-            BallGrid_t *bg = (BallGrid_t *)rsGetElementAt(gGrid, x, y);
-            bg->cacheIdx = gridIdx;
-
-            int idx = bg->idx;
-            while (idx >= 0) {
-                const Ball_t * bPtr = &balls[idx];
-                gGridCache[gridIdx++] = bPtr->position;
-                idx = bPtr->next;
-            }
-        }
-    }
-
-
-    rsForEach(physics_script, ain, ain);
-
-    for (uint32_t ct=0; ct < dimX; ct++) {
-        point[ct].position = balls[ct].position;
-        point[ct].color = balls[ct].color;
-    }
-
-    rsgBindProgramFragment(gPFPoints);
-    rsgDrawMesh(partMesh);
-    return 1;
-}
-
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh
deleted file mode 100644
index ebe23f8..0000000
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/balls.rsh
+++ /dev/null
@@ -1,19 +0,0 @@
-
-typedef struct __attribute__((packed, aligned(4))) Ball {
-    float2 delta;
-    float2 position;
-    uchar4 color;
-    float pressure;
-    //float size;
-    int32_t next;
-    //int arcID;
-    //float arcStr;
-} Ball_t;
-Ball_t *balls;
-
-
-typedef struct BallGrid {
-    int32_t idx;
-    int32_t count;
-    int32_t cacheIdx;
-} BallGrid_t;
diff --git a/tests/RenderScriptTests/ComputeBenchmark/Android.mk b/tests/RenderScriptTests/ComputeBenchmark/Android.mk
deleted file mode 100644
index 8d47e89..0000000
--- a/tests/RenderScriptTests/ComputeBenchmark/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsComputeBenchmark
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ComputeBenchmark/AndroidManifest.xml b/tests/RenderScriptTests/ComputeBenchmark/AndroidManifest.xml
deleted file mode 100644
index c8fcc17..0000000
--- a/tests/RenderScriptTests/ComputeBenchmark/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.computebench">
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-sdk android:minSdkVersion="17" />
-    <application android:label="_RS_Compute_Bench">
-        <activity android:name="ComputeBench">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/ComputeBenchmark/res/layout/main.xml b/tests/RenderScriptTests/ComputeBenchmark/res/layout/main.xml
deleted file mode 100644
index 9e9dab8..0000000
--- a/tests/RenderScriptTests/ComputeBenchmark/res/layout/main.xml
+++ /dev/null
@@ -1,31 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-    <ImageView
-        android:id="@+id/displayin"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-    <ImageView
-        android:id="@+id/displayout"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-</LinearLayout>
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/Benchmark.java b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/Benchmark.java
deleted file mode 100644
index ec80719..0000000
--- a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/Benchmark.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.computebench;
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class Benchmark implements Runnable {
-    private final RenderScript mRS;
-    private ScriptC_compute_benchmark mScript;
-
-    public Benchmark(RenderScript rs, Resources res) {
-        mRS = rs;
-        mScript = new ScriptC_compute_benchmark(mRS, res, R.raw.compute_benchmark);
-    }
-
-    public void run() {
-        long t = java.lang.System.currentTimeMillis();
-        mScript.invoke_bench();
-        mRS.finish();
-        t = java.lang.System.currentTimeMillis() - t;
-        android.util.Log.v("ComputeBench", "Total benchmark took " + t + " ms");
-    }
-
-}
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/ComputeBench.java b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/ComputeBench.java
deleted file mode 100644
index 2d3e843..0000000
--- a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/ComputeBench.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.computebench;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.renderscript.RenderScript;
-
-public class ComputeBench extends Activity {
-    private RenderScript mRS;
-    private Benchmark mBenchmark;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        mRS = RenderScript.create(this);
-
-        mBenchmark = new Benchmark(mRS, getResources());
-        mBenchmark.run();
-    }
-}
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
deleted file mode 100644
index 2ee56ec..0000000
--- a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
+++ /dev/null
@@ -1,407 +0,0 @@
-// 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.computebench)
-
-// Test configuration (accessible from Java)
-uint priming_runs   = 1000000;
-uint timing_runs    = 5000000;
-
-// Reused variables
-
-static volatile int64_t bench_time;
-static float inv_timing_runs;
-
-#define DECL_VAR_SET(prefix)                \
-static volatile float prefix##_f_1 = 1;     \
-static volatile float2 prefix##_f_2 = 1;    \
-static volatile float3 prefix##_f_3 = 1;    \
-static volatile float4 prefix##_f_4 = 1;    \
-static volatile char prefix##_c_1 = 1;      \
-static volatile char2 prefix##_c_2 = 1;     \
-static volatile char3 prefix##_c_3 = 1;     \
-static volatile char4 prefix##_c_4 = 1;     \
-static volatile uchar prefix##_uc_1 = 1;    \
-static volatile uchar2 prefix##_uc_2 = 1;   \
-static volatile uchar3 prefix##_uc_3 = 1;   \
-static volatile uchar4 prefix##_uc_4 = 1;   \
-static volatile short prefix##_s_1 = 1;     \
-static volatile short2 prefix##_s_2 = 1;    \
-static volatile short3 prefix##_s_3 = 1;    \
-static volatile short4 prefix##_s_4 = 1;    \
-static volatile ushort prefix##_us_1 = 1;   \
-static volatile ushort2 prefix##_us_2 = 1;  \
-static volatile ushort3 prefix##_us_3 = 1;  \
-static volatile ushort4 prefix##_us_4 = 1;  \
-static volatile int prefix##_i_1 = 1;       \
-static volatile int2 prefix##_i_2 = 1;      \
-static volatile int3 prefix##_i_3 = 1;      \
-static volatile int4 prefix##_i_4 = 1;      \
-static volatile uint prefix##_ui_1 = 1;     \
-static volatile uint2 prefix##_ui_2 = 1;    \
-static volatile uint3 prefix##_ui_3 = 1;    \
-static volatile uint4 prefix##_ui_4 = 1;    \
-static volatile long prefix##_l_1 = 1;      \
-static volatile long2 prefix##_l_2 = 1;     \
-static volatile long3 prefix##_l_3 = 1;     \
-static volatile long4 prefix##_l_4 = 1;     \
-static volatile ulong prefix##_ul_1 = 1;    \
-static volatile ulong2 prefix##_ul_2 = 1;   \
-static volatile ulong3 prefix##_ul_3 = 1;   \
-static volatile ulong4 prefix##_ul_4 = 1;   \
-
-DECL_VAR_SET(res)
-DECL_VAR_SET(src1)
-DECL_VAR_SET(src2)
-DECL_VAR_SET(src3)
-
-
-// Testing macros
-
-#define RUN_BENCH(line, op)                         \
-    for (int i = priming_runs - 1; i >= 0; --i) {   \
-        line;                                       \
-    }                                               \
-    bench_time = rsUptimeMillis();                  \
-    for (int i = timing_runs - 1; i >= 0; --i) {    \
-        line;                                       \
-    }                                               \
-    bench_time = rsUptimeMillis() - bench_time;     \
-    rsDebug("    " op " took ns", (float)bench_time * inv_timing_runs);
-
-#define BENCH_BASIC_OP_TYPE(op, type)                                                               \
-    RUN_BENCH(res_##type##_1 = src1_##type##_1 op src2_##type##_1, #type "1 " #op " " #type "1")    \
-    RUN_BENCH(res_##type##_2 = src1_##type##_2 op src2_##type##_2, #type "2 " #op " " #type "2")    \
-    RUN_BENCH(res_##type##_3 = src1_##type##_3 op src2_##type##_3, #type "3 " #op " " #type "3")    \
-    RUN_BENCH(res_##type##_4 = src1_##type##_4 op src2_##type##_4, #type "4 " #op " " #type "4")    \
-
-#define BENCH_BASIC_INT_OP(op)                                  \
-    rsDebug("Testing basic operation " #op, 0);                 \
-    BENCH_BASIC_OP_TYPE(op, c)                                  \
-    BENCH_BASIC_OP_TYPE(op, uc)                                 \
-    BENCH_BASIC_OP_TYPE(op, s)                                  \
-    BENCH_BASIC_OP_TYPE(op, us)                                 \
-    BENCH_BASIC_OP_TYPE(op, i)                                  \
-    BENCH_BASIC_OP_TYPE(op, ui)                                 \
-    RUN_BENCH(res_l_1 = src1_l_1 op src2_l_1, "l1 " #op " l1")  \
-    RUN_BENCH(res_ul_1 = src1_ul_1 op src2_ul_1, "ul1 " #op " ul1")
-
-#define BENCH_BASIC_OP(op)      \
-    BENCH_BASIC_INT_OP(op)      \
-    BENCH_BASIC_OP_TYPE(op, f)
-
-#define BENCH_CVT(to, from, type)                                                                           \
-    rsDebug("Testing convert from " #from " to " #to, 0);                                                   \
-    RUN_BENCH(res_##to##_1 = (type)src1_##from##_1, "(" #to ")" #from)                                      \
-    RUN_BENCH(res_##to##_2 = convert_##type##2(src1_##from##_2), #to "2 convert_" #type "2(" #from "2)")    \
-    RUN_BENCH(res_##to##_3 = convert_##type##3(src1_##from##_3), #to "3 convert_" #type "3(" #from "3)")    \
-    RUN_BENCH(res_##to##_4 = convert_##type##4(src1_##from##_4), #to "4 convert_" #type "4(" #from "4)")
-
-#define BENCH_CVT_MATRIX(to, type)  \
-    BENCH_CVT(to, c, type);         \
-    BENCH_CVT(to, uc, type);        \
-    BENCH_CVT(to, s, type);         \
-    BENCH_CVT(to, us, type);        \
-    BENCH_CVT(to, i, type);         \
-    BENCH_CVT(to, ui, type);        \
-    BENCH_CVT(to, f, type);         \
-
-#define BENCH_XN_FUNC_YN(typeout, fnc, typein)                                                  \
-    RUN_BENCH(res_##typeout##_1 = fnc(src1_##typein##_1);, #typeout "1 " #fnc "(" #typein "1)") \
-    RUN_BENCH(res_##typeout##_2 = fnc(src1_##typein##_2);, #typeout "2 " #fnc "(" #typein "2)") \
-    RUN_BENCH(res_##typeout##_3 = fnc(src1_##typein##_3);, #typeout "3 " #fnc "(" #typein "3)") \
-    RUN_BENCH(res_##typeout##_4 = fnc(src1_##typein##_4);, #typeout "4 " #fnc "(" #typein "4)")
-
-#define BENCH_XN_FUNC_XN_XN(type, fnc)                                                                              \
-    RUN_BENCH(res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1), #type "1 " #fnc "(" #type "1, " #type "1)")   \
-    RUN_BENCH(res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2), #type "2 " #fnc "(" #type "2, " #type "2)")   \
-    RUN_BENCH(res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3), #type "3 " #fnc "(" #type "3, " #type "3)")   \
-    RUN_BENCH(res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4), #type "4 " #fnc "(" #type "4, " #type "4)")   \
-
-#define BENCH_X_FUNC_X_X_X(type, fnc)   \
-    RUN_BENCH(res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src3_##type##_1), #type "1 " #fnc "(" #type "1, " #type "1, " #type "1)")
-
-#define BENCH_IN_FUNC_IN(fnc)       \
-    rsDebug("Testing " #fnc, 0);    \
-    BENCH_XN_FUNC_YN(uc, fnc, uc)   \
-    BENCH_XN_FUNC_YN(c, fnc, c)     \
-    BENCH_XN_FUNC_YN(us, fnc, us)   \
-    BENCH_XN_FUNC_YN(s, fnc, s)     \
-    BENCH_XN_FUNC_YN(ui, fnc, ui)   \
-    BENCH_XN_FUNC_YN(i, fnc, i)
-
-#define BENCH_UIN_FUNC_IN(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    BENCH_XN_FUNC_YN(uc, fnc, c)    \
-    BENCH_XN_FUNC_YN(us, fnc, s)    \
-    BENCH_XN_FUNC_YN(ui, fnc, i)    \
-
-#define BENCH_IN_FUNC_IN_IN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    BENCH_XN_FUNC_XN_XN(uc, fnc)    \
-    BENCH_XN_FUNC_XN_XN(c, fnc)     \
-    BENCH_XN_FUNC_XN_XN(us, fnc)    \
-    BENCH_XN_FUNC_XN_XN(s, fnc)     \
-    BENCH_XN_FUNC_XN_XN(ui, fnc)    \
-    BENCH_XN_FUNC_XN_XN(i, fnc)
-
-#define BENCH_I_FUNC_I_I_I(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    BENCH_X_FUNC_X_X_X(uc, fnc)     \
-    BENCH_X_FUNC_X_X_X(c, fnc)      \
-    BENCH_X_FUNC_X_X_X(us, fnc)     \
-    BENCH_X_FUNC_X_X_X(s, fnc)      \
-    BENCH_X_FUNC_X_X_X(ui, fnc)     \
-    BENCH_X_FUNC_X_X_X(i, fnc)
-
-#define BENCH_FN_FUNC_FN(fnc)                               \
-    rsDebug("Testing " #fnc, 0);                            \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1), "f1 " #fnc "(f1)")   \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2), "f2 " #fnc "(f2)")   \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3), "f3 " #fnc "(f3)")   \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4), "f4 " #fnc "(f4)")
-
-#define BENCH_FN_FUNC_FN_PFN(fnc)                                                   \
-    rsDebug("Testing " #fnc, 0);                                                    \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, (float*) &src2_f_1), "f1 " #fnc "(f1, f1*)")  \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, (float2*) &src2_f_2), "f2 " #fnc "(f2, f2*)") \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, (float3*) &src2_f_3), "f3 " #fnc "(f3, f3*)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, (float4*) &src2_f_4), "f4 " #fnc "(f4, f4*)")
-
-#define BENCH_FN_FUNC_FN_FN(fnc)                                        \
-    rsDebug("Testing " #fnc, 0);                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1), "f1 " #fnc "(f1, f1)") \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2), "f2 " #fnc "(f2, f2)") \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3), "f3 " #fnc "(f3, f3)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4), "f4 " #fnc "(f4, f4)")
-
-#define BENCH_F34_FUNC_F34_F34(fnc)                                     \
-    rsDebug("Testing " #fnc, 0);                                        \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3), "f3 " #fnc "(f3, f3)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4), "f4 " #fnc "(f4, f4)")
-
-#define BENCH_FN_FUNC_FN_F(fnc)                                         \
-    rsDebug("Testing " #fnc, 0);                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1), "f1 " #fnc "(f1, f1)") \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_1), "f2 " #fnc "(f2, f1)") \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_1), "f3 " #fnc "(f3, f1)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_1), "f4 " #fnc "(f4, f1)")
-
-#define BENCH_F_FUNC_FN(fnc)                                \
-    rsDebug("Testing " #fnc, 0);                            \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1), "f1 " #fnc "(f1)")   \
-    RUN_BENCH(res_f_1 = fnc(src1_f_2), "f1 " #fnc "(f2)")   \
-    RUN_BENCH(res_f_1 = fnc(src1_f_3), "f1 " #fnc "(f3)")   \
-    RUN_BENCH(res_f_1 = fnc(src1_f_4), "f1 " #fnc "(f4)")
-
-#define BENCH_F_FUNC_FN_FN(fnc)                                         \
-    rsDebug("Testing " #fnc, 0);                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1), "f1 " #fnc "(f1, f1)") \
-    RUN_BENCH(res_f_1 = fnc(src1_f_2, src2_f_2), "f1 " #fnc "(f2, f2)") \
-    RUN_BENCH(res_f_1 = fnc(src1_f_3, src2_f_3), "f1 " #fnc "(f3, f3)") \
-    RUN_BENCH(res_f_1 = fnc(src1_f_4, src2_f_4), "f1 " #fnc "(f4, f4)")
-
-#define BENCH_FN_FUNC_FN_IN(fnc)                                        \
-    rsDebug("Testing " #fnc, 0);                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src1_i_1), "f1 " #fnc "(f1, i1)") \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src1_i_2), "f2 " #fnc "(f2, i2)") \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src1_i_3), "f3 " #fnc "(f3, i3)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src1_i_4), "f4 " #fnc "(f4, i4)")
-
-#define BENCH_FN_FUNC_FN_I(fnc)                                         \
-    rsDebug("Testing " #fnc, 0);                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src1_i_1), "f1 " #fnc "(f1, i1)") \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src1_i_1), "f2 " #fnc "(f2, i1)") \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src1_i_1), "f3 " #fnc "(f3, i1)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src1_i_1), "f4 " #fnc "(f4, i1)")
-
-#define BENCH_FN_FUNC_FN_FN_FN(fnc)                                                     \
-    rsDebug("Testing " #fnc, 0);                                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1, src3_f_1), "f1 " #fnc "(f1, f1, f1)")   \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2, src3_f_2), "f2 " #fnc "(f2, f2, f2)")   \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3, src3_f_3), "f3 " #fnc "(f3, f3, f3)")   \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4, src3_f_4), "f4 " #fnc "(f4, f4, f4)")
-
-#define BENCH_FN_FUNC_FN_FN_F(fnc)                                                      \
-    rsDebug("Testing " #fnc, 0);                                                        \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1, src3_f_1), "f1 " #fnc "(f1, f1, f1)")   \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2, src3_f_1), "f2 " #fnc "(f2, f2, f1)")   \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3, src3_f_1), "f3 " #fnc "(f3, f3, f1)")   \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4, src3_f_1), "f4 " #fnc "(f4, f4, f1)")
-
-#define BENCH_FN_FUNC_FN_PIN(fnc)                                                   \
-    rsDebug("Testing " #fnc, 0);                                                    \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, (int*) &src1_i_1), "f1 " #fnc "(f1, i1*)")    \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, (int2*) &src1_i_2), "f2 " #fnc "(f2, i2*)")   \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, (int3*) &src1_i_3), "f3 " #fnc "(f3, i3*)")   \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, (int4*) &src1_i_4), "f4 " #fnc "(f4, i4*)")
-
-#define BENCH_FN_FUNC_FN_FN_PIN(fnc)                                                            \
-    rsDebug("Testing " #fnc, 0);                                                                \
-    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1, (int*) &src1_i_1), "f1 " #fnc "(f1, f1, i1*)")  \
-    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2, (int2*) &src1_i_2), "f2 " #fnc "(f2, f2, i2*)") \
-    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3, (int3*) &src1_i_3), "f3 " #fnc "(f3, f3, i3*)") \
-    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4, (int4*) &src1_i_4), "f4 " #fnc "(f4, f4, i4*)")
-
-#define BENCH_IN_FUNC_FN(fnc)                               \
-    rsDebug("Testing " #fnc, 0);                            \
-    RUN_BENCH(res_i_1 = fnc(src1_f_1), "i1 " #fnc "(f1)")   \
-    RUN_BENCH(res_i_2 = fnc(src1_f_2), "i2 " #fnc "(f2)")   \
-    RUN_BENCH(res_i_3 = fnc(src1_f_3), "i3 " #fnc "(f3)")   \
-    RUN_BENCH(res_i_4 = fnc(src1_f_4), "i4 " #fnc "(f4)")
-
-
-// Testing functions
-
-static void bench_basic_operators() {
-    int i = 0;
-    BENCH_BASIC_OP(+);
-    BENCH_BASIC_OP(-);
-    BENCH_BASIC_OP(*);
-    BENCH_BASIC_OP(/);
-    BENCH_BASIC_INT_OP(%);
-    BENCH_BASIC_INT_OP(<<);
-    BENCH_BASIC_INT_OP(>>);
-}
-
-static void bench_convert() {
-    BENCH_CVT_MATRIX(c, char);
-    BENCH_CVT_MATRIX(uc, uchar);
-    BENCH_CVT_MATRIX(s, short);
-    BENCH_CVT_MATRIX(us, ushort);
-    BENCH_CVT_MATRIX(i, int);
-    BENCH_CVT_MATRIX(ui, uint);
-    BENCH_CVT_MATRIX(f, float);
-}
-
-static void bench_int_math() {
-    BENCH_UIN_FUNC_IN(abs);
-    BENCH_IN_FUNC_IN(clz);
-    BENCH_IN_FUNC_IN_IN(min);
-    BENCH_IN_FUNC_IN_IN(max);
-    BENCH_I_FUNC_I_I_I(rsClamp);
-}
-
-static void bench_fp_math() {
-    BENCH_FN_FUNC_FN(acos);
-    BENCH_FN_FUNC_FN(acosh);
-    BENCH_FN_FUNC_FN(acospi);
-    BENCH_FN_FUNC_FN(asin);
-    BENCH_FN_FUNC_FN(asinh);
-    BENCH_FN_FUNC_FN(asinpi);
-    BENCH_FN_FUNC_FN(atan);
-    BENCH_FN_FUNC_FN_FN(atan2);
-    BENCH_FN_FUNC_FN(atanh);
-    BENCH_FN_FUNC_FN(atanpi);
-    BENCH_FN_FUNC_FN_FN(atan2pi);
-    BENCH_FN_FUNC_FN(cbrt);
-    BENCH_FN_FUNC_FN(ceil);
-    BENCH_FN_FUNC_FN_FN_FN(clamp);
-    BENCH_FN_FUNC_FN_FN_F(clamp);
-    BENCH_FN_FUNC_FN_FN(copysign);
-    BENCH_FN_FUNC_FN(cos);
-    BENCH_FN_FUNC_FN(cosh);
-    BENCH_FN_FUNC_FN(cospi);
-    BENCH_F34_FUNC_F34_F34(cross);
-    BENCH_FN_FUNC_FN(degrees);
-    BENCH_F_FUNC_FN_FN(distance);
-    BENCH_F_FUNC_FN_FN(dot);
-    BENCH_FN_FUNC_FN(erfc);
-    BENCH_FN_FUNC_FN(erf);
-    BENCH_FN_FUNC_FN(exp);
-    BENCH_FN_FUNC_FN(exp2);
-    BENCH_FN_FUNC_FN(exp10);
-    BENCH_FN_FUNC_FN(expm1);
-    BENCH_FN_FUNC_FN(fabs);
-    BENCH_FN_FUNC_FN_FN(fdim);
-    BENCH_FN_FUNC_FN(floor);
-    BENCH_FN_FUNC_FN_FN_FN(fma);
-    BENCH_FN_FUNC_FN_FN(fmax);
-    BENCH_FN_FUNC_FN_F(fmax);
-    BENCH_FN_FUNC_FN_FN(fmin);
-    BENCH_FN_FUNC_FN_F(fmin);
-    BENCH_FN_FUNC_FN_FN(fmod);
-    BENCH_FN_FUNC_FN_PFN(fract);
-    BENCH_FN_FUNC_FN_PIN(frexp);
-    BENCH_FN_FUNC_FN_FN(hypot);
-    BENCH_IN_FUNC_FN(ilogb);
-    BENCH_FN_FUNC_FN_IN(ldexp);
-    BENCH_FN_FUNC_FN_I(ldexp);
-    BENCH_F_FUNC_FN(length);
-    BENCH_FN_FUNC_FN(lgamma);
-    BENCH_FN_FUNC_FN_PIN(lgamma);
-    BENCH_FN_FUNC_FN(log);
-    BENCH_FN_FUNC_FN(log2);
-    BENCH_FN_FUNC_FN(log10);
-    BENCH_FN_FUNC_FN(log1p);
-    BENCH_FN_FUNC_FN(logb);
-    BENCH_FN_FUNC_FN_FN_FN(mad);
-    BENCH_FN_FUNC_FN_FN(max);
-    BENCH_FN_FUNC_FN_F(max);
-    BENCH_FN_FUNC_FN_FN(min);
-    BENCH_FN_FUNC_FN_F(min);
-    BENCH_FN_FUNC_FN_FN_FN(mix);
-    BENCH_FN_FUNC_FN_FN_F(mix);
-    BENCH_FN_FUNC_FN_PFN(modf);
-    BENCH_FN_FUNC_FN_FN(nextafter);
-    BENCH_FN_FUNC_FN(normalize);
-    BENCH_FN_FUNC_FN_FN(pow);
-    BENCH_FN_FUNC_FN_IN(pown);
-    BENCH_FN_FUNC_FN_FN(powr);
-    BENCH_FN_FUNC_FN(radians);
-    BENCH_FN_FUNC_FN_FN(remainder);
-    BENCH_FN_FUNC_FN_FN_PIN(remquo);
-    BENCH_FN_FUNC_FN(rint);
-    BENCH_FN_FUNC_FN_IN(rootn);
-    BENCH_FN_FUNC_FN(round);
-    BENCH_FN_FUNC_FN(rsqrt);
-    BENCH_FN_FUNC_FN(sign);
-    BENCH_FN_FUNC_FN(sin);
-    BENCH_FN_FUNC_FN_PFN(sincos);
-    BENCH_FN_FUNC_FN(sinh);
-    BENCH_FN_FUNC_FN(sinpi);
-    BENCH_FN_FUNC_FN(sqrt);
-    BENCH_FN_FUNC_FN_FN(step);
-    BENCH_FN_FUNC_FN_F(step);
-    BENCH_FN_FUNC_FN(tan);
-    BENCH_FN_FUNC_FN(tanh);
-    BENCH_FN_FUNC_FN(tanpi);
-    BENCH_FN_FUNC_FN(tgamma);
-    BENCH_FN_FUNC_FN(trunc);
-}
-
-static void bench_approx_math() {
-    BENCH_FN_FUNC_FN(half_recip);
-    BENCH_FN_FUNC_FN(half_sqrt);
-    BENCH_FN_FUNC_FN(half_rsqrt);
-    BENCH_FN_FUNC_FN(fast_length);
-    BENCH_FN_FUNC_FN_FN(fast_distance);
-    BENCH_FN_FUNC_FN(fast_normalize);
-}
-
-void bench() {
-    rsDebug("RS Compute Benchmark", 0);
-    rsDebug("Current configuration:", 0);
-    rsDebug("Priming runs", priming_runs);
-    rsDebug("Timing runs", timing_runs);
-    rsDebug("Beginning test", 0);
-    inv_timing_runs = 1000000.f / (float)timing_runs;
-    bench_basic_operators();
-    bench_convert();
-    bench_int_math();
-    bench_fp_math();
-    bench_approx_math();
-}
-
diff --git a/tests/RenderScriptTests/ComputePerf/Android.mk b/tests/RenderScriptTests/ComputePerf/Android.mk
deleted file mode 100644
index 6ed5884..0000000
--- a/tests/RenderScriptTests/ComputePerf/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# Copyright (C) 2011 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsComputePerf
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
deleted file mode 100644
index a9193b5..0000000
--- a/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.computeperf">
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    
-    <uses-sdk android:minSdkVersion="14" />
-    <application android:label="Compute Perf">
-        <activity android:name="ComputePerf">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/ComputePerf/res/layout/main.xml b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
deleted file mode 100644
index 61cd24d..0000000
--- a/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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">
-
-    <ImageView
-        android:id="@+id/displayin"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-    <ImageView
-        android:id="@+id/displayout"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-</LinearLayout>
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
deleted file mode 100644
index 5446f66..0000000
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.computeperf;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.renderscript.RenderScript;
-import android.renderscript.Allocation;
-import android.util.Log;
-import android.widget.ImageView;
-
-public class ComputePerf extends Activity {
-    private LaunchTest mLT;
-    private Mandelbrot mMandel;
-    private RenderScript mRS;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        final int numTries = 100;
-
-        long timesXLW = 0;
-        long timesXYW = 0;
-
-        mRS = RenderScript.create(this);
-        mLT = new LaunchTest(mRS, getResources());
-        mLT.XLW();
-        mLT.XYW();
-        for (int i = 0; i < numTries; i++) {
-            timesXLW += mLT.XLW();
-            timesXYW += mLT.XYW();
-        }
-
-        timesXLW /= numTries;
-        timesXYW /= numTries;
-
-        // XLW and XYW running times should match pretty closely
-        Log.v("ComputePerf", "xlw launch test " + timesXLW + "ms");
-        Log.v("ComputePerf", "xyw launch test " + timesXYW + "ms");
-
-        mMandel = new Mandelbrot(mRS, getResources());
-        mMandel.run();
-    }
-}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
deleted file mode 100644
index e2312ba..0000000
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.computeperf;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class LaunchTest {
-    private RenderScript mRS;
-    private Allocation mAllocationX;
-    private Allocation mAllocationXY;
-    private ScriptC_launchtestxlw mScript_xlw;
-    private ScriptC_launchtestxyw mScript_xyw;
-
-    LaunchTest(RenderScript rs, Resources res) {
-        mRS = rs;
-        mScript_xlw = new ScriptC_launchtestxlw(mRS, res, R.raw.launchtestxlw);
-        mScript_xyw = new ScriptC_launchtestxyw(mRS, res, R.raw.launchtestxyw);
-        final int dim = mScript_xlw.get_dim();
-
-        mAllocationX = Allocation.createSized(rs, Element.U8(rs), dim);
-        Type.Builder tb = new Type.Builder(rs, Element.U8(rs));
-        tb.setX(dim);
-        tb.setY(dim);
-        mAllocationXY = Allocation.createTyped(rs, tb.create());
-        mScript_xlw.bind_buf(mAllocationXY);
-    }
-
-    public long XLW() {
-        long t = java.lang.System.currentTimeMillis();
-        mScript_xlw.forEach_root(mAllocationX);
-        mRS.finish();
-        t = java.lang.System.currentTimeMillis() - t;
-        return t;
-    }
-
-    public long XYW() {
-        long t = java.lang.System.currentTimeMillis();
-        mScript_xyw.forEach_root(mAllocationXY);
-        mRS.finish();
-        t = java.lang.System.currentTimeMillis() - t;
-        return t;
-    }
-}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/Mandelbrot.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/Mandelbrot.java
deleted file mode 100644
index ea1cd62..0000000
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/Mandelbrot.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2011 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.example.android.rs.computeperf;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class Mandelbrot implements Runnable {
-    private RenderScript mRS;
-    private Allocation mAllocationXY;
-    private ScriptC_mandelbrot mScript;
-
-    Mandelbrot(RenderScript rs, Resources res) {
-        mRS = rs;
-        mScript = new ScriptC_mandelbrot(mRS, res, R.raw.mandelbrot);
-
-        Type.Builder tb = new Type.Builder(rs, Element.U8_4(rs));
-        tb.setX(mScript.get_gDimX());
-        tb.setY(mScript.get_gDimY());
-        mAllocationXY = Allocation.createTyped(rs, tb.create());
-    }
-
-    public void run() {
-        long t = java.lang.System.currentTimeMillis();
-        mScript.forEach_root(mAllocationXY);
-        mRS.finish();
-        t = java.lang.System.currentTimeMillis() - t;
-        android.util.Log.v("ComputePerf", "mandelbrot  ms " + t);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
deleted file mode 100644
index 7b81dfe..0000000
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.computeperf)
-
-const int dim = 2048;
-uint8_t *buf;
-
-void root(uchar *v_out, uint32_t x) {
-    uint8_t *p = buf;
-    p += x * dim;
-    for (int i=0; i<dim; i++) {
-        p[i] = 1;
-    }
-}
-
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
deleted file mode 100644
index 7f7aa95..0000000
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.computeperf)
-
-void root(uchar *v_out, uint32_t x, uint32_t y) {
-    *v_out = 0;
-}
-
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
deleted file mode 100644
index 0ffb0e5..0000000
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2011 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.computeperf)
-
-const int gMaxIteration = 500;
-const int gDimX = 1024;
-const int gDimY = 1024;
-
-void root(uchar4 *v_out, uint32_t x, uint32_t y) {
-    float2 p;
-    p.x = -2.5f + ((float)x / gDimX) * 3.5f;
-    p.y = -1.f + ((float)y / gDimY) * 2.f;
-
-    float2 t = 0;
-    float2 t2 = t * t;
-    int iteration = 0;
-    while((t2.x + t2.y < 4.f) && (iteration < gMaxIteration)) {
-        float xtemp = t2.x - t2.y + p.x;
-        t.y = 2 * t.x * t.y + p.y;
-        t.x = xtemp;
-        iteration++;
-        t2 = t * t;
-    }
-
-    if(iteration >= gMaxIteration) {
-        *v_out = 0;
-    } else {
-        *v_out = (uchar4){iteration & 0xff, (iteration >> 6) & 0xff, 0x8f, 0xff};
-    }
-}
diff --git a/tests/RenderScriptTests/FBOTest/Android.mk b/tests/RenderScriptTests/FBOTest/Android.mk
index 434d592..7a578d9 100644
--- a/tests/RenderScriptTests/FBOTest/Android.mk
+++ b/tests/RenderScriptTests/FBOTest/Android.mk
@@ -23,4 +23,6 @@
 
 LOCAL_PACKAGE_NAME := FBOTest
 
+LOCAL_SDK_VERSION := 17
+
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Fountain/Android.mk b/tests/RenderScriptTests/Fountain/Android.mk
index 4a6560b..0517aef 100644
--- a/tests/RenderScriptTests/Fountain/Android.mk
+++ b/tests/RenderScriptTests/Fountain/Android.mk
@@ -21,8 +21,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
-# TODO: build fails with this set
-# LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 17
 
 LOCAL_PACKAGE_NAME := RsFountain
 
diff --git a/tests/RenderScriptTests/HelloWorld/Android.mk b/tests/RenderScriptTests/HelloWorld/Android.mk
index 54824f4..c1c08ec 100644
--- a/tests/RenderScriptTests/HelloWorld/Android.mk
+++ b/tests/RenderScriptTests/HelloWorld/Android.mk
@@ -23,6 +23,6 @@
 
 LOCAL_PACKAGE_NAME := RsHelloWorld
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 17
 
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ImageProcessing/Android.mk b/tests/RenderScriptTests/ImageProcessing/Android.mk
deleted file mode 100644
index d7486e8..0000000
--- a/tests/RenderScriptTests/ImageProcessing/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Copyright (C) 2009 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_PACKAGE_NAME := ImageProcessing
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
deleted file mode 100644
index d51fa39..0000000
--- a/tests/RenderScriptTests/ImageProcessing/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.image">
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-sdk android:minSdkVersion="17" />
-    <application android:label="Image Processing"
-                 android:hardwareAccelerated="true">
-        <uses-library android:name="android.test.runner" />
-        <activity android:name="ImageProcessingActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-    <instrumentation android:name=".ImageProcessingTestRunner"
-      android:targetPackage="com.android.rs.image"
-      android:label="Test runner for Image Processing Benchmark Test"
-    />
-</manifest>
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg
deleted file mode 100644
index 05d3ee2..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067b.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067b.jpg
deleted file mode 100644
index aed0781..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067b.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
deleted file mode 100644
index f0a2b92..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:id="@+id/toplevel">
-    <SurfaceView
-        android:id="@+id/surface"
-        android:layout_width="1dip"
-        android:layout_height="1dip" />
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="vertical"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
-            <ImageView
-                android:id="@+id/display"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-                    <Button
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/benchmark"
-                        android:onClick="benchmark"/>
-                    <TextView
-                        android:id="@+id/benchmarkText"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/saturation"/>
-            </LinearLayout>
-            <Spinner
-                android:id="@+id/filterselection"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <Spinner
-                android:id="@+id/spinner1"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider1Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/saturation"/>
-             <SeekBar
-                android:id="@+id/slider1"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider2Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/gamma"/>
-            <SeekBar
-                android:id="@+id/slider2"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider3Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:textSize="8pt"
-                android:text="@string/out_white"/>
-            <SeekBar
-                android:id="@+id/slider3"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider4Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/slider4"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider5Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/slider5"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <Button
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/benchmark_all"
-                    android:onClick="benchmark_all"/>
-            </LinearLayout>
-    </ScrollView>
-</LinearLayout>
-
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/spinner_layout.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/spinner_layout.xml
deleted file mode 100644
index 8196bbf..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/spinner_layout.xml
+++ /dev/null
@@ -1,23 +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"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:padding="10dp"
-    android:textSize="16sp"
-/>
diff --git a/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
deleted file mode 100644
index a7dd165..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/values/strings.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2008 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- General -->
-    <skip />
-    <!--slider label -->
-    <string name="blur_description">Blur Radius</string>
-    <string name="in_white">In White</string>
-    <string name="out_white">Out White</string>
-    <string name="in_black">In Black</string>
-    <string name="out_black">Out Black</string>
-    <string name="gamma">Gamma</string>
-    <string name="saturation">Saturation</string>
-    <string name="benchmark">Benchmark</string>
-    <string name="benchmark_all">Benchmark All</string>
-
-</resources>
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/BWFilter.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/BWFilter.java
deleted file mode 100644
index 4fd63bf..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/BWFilter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-
-public class BWFilter extends TestBase {
-    private ScriptC_bwfilter mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_bwfilter(mRS);
-    }
-
-    public void runTest() {
-        mScript.invoke_prepareBwFilter(50, 50, 50);
-        mScript.forEach_bwFilterKernel(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java
deleted file mode 100644
index 2303fc3..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-import java.lang.Short;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.ScriptGroup;
-import android.renderscript.ScriptIntrinsicBlend;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.view.View;
-import android.widget.Spinner;
-
-public class Blend extends TestBase {
-    private ScriptIntrinsicBlend mBlend;
-    private ScriptC_blend mBlendHelper;
-    private short image1Alpha = 128;
-    private short image2Alpha = 128;
-
-    String mIntrinsicNames[];
-
-    private Allocation image1;
-    private Allocation image2;
-    private int currentIntrinsic = 0;
-
-    private AdapterView.OnItemSelectedListener mIntrinsicSpinnerListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-                    currentIntrinsic = pos;
-                    if (mRS != null) {
-                        runTest();
-                        act.updateDisplay();
-                    }
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-            };
-
-    public void createTest(android.content.res.Resources res) {
-        mBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS));
-        mBlendHelper = new ScriptC_blend(mRS);
-        mBlendHelper.set_alpha((short)128);
-
-        image1 = Allocation.createTyped(mRS, mInPixelsAllocation.getType());
-        image2 = Allocation.createTyped(mRS, mInPixelsAllocation2.getType());
-
-        mIntrinsicNames = new String[14];
-        mIntrinsicNames[0] = "Source";
-        mIntrinsicNames[1] = "Destination";
-        mIntrinsicNames[2] = "Source Over";
-        mIntrinsicNames[3] = "Destination Over";
-        mIntrinsicNames[4] = "Source In";
-        mIntrinsicNames[5] = "Destination In";
-        mIntrinsicNames[6] = "Source Out";
-        mIntrinsicNames[7] = "Destination Out";
-        mIntrinsicNames[8] = "Source Atop";
-        mIntrinsicNames[9] = "Destination Atop";
-        mIntrinsicNames[10] = "XOR";
-        mIntrinsicNames[11] = "Add";
-        mIntrinsicNames[12] = "Subtract";
-        mIntrinsicNames[13] = "Multiply";
-    }
-
-    public boolean onSpinner1Setup(Spinner s) {
-        s.setAdapter(new ArrayAdapter<String>(
-            act, R.layout.spinner_layout, mIntrinsicNames));
-        s.setOnItemSelectedListener(mIntrinsicSpinnerListener);
-        return true;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Image 1 Alpha");
-        b.setMax(255);
-        b.setProgress(image1Alpha);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        image1Alpha = (short)progress;
-    }
-
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Image 2 Alpha");
-        b.setMax(255);
-        b.setProgress(image2Alpha);
-        return true;
-    }
-
-    public void onBar2Changed(int progress) {
-        image2Alpha = (short)progress;
-    }
-
-    public void runTest() {
-        image1.copy2DRangeFrom(0, 0, mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), mInPixelsAllocation, 0, 0);
-        image2.copy2DRangeFrom(0, 0, mInPixelsAllocation2.getType().getX(), mInPixelsAllocation2.getType().getY(), mInPixelsAllocation2, 0, 0);
-
-        mBlendHelper.set_alpha(image1Alpha);
-        mBlendHelper.forEach_setImageAlpha(image1);
-
-        mBlendHelper.set_alpha(image2Alpha);
-        mBlendHelper.forEach_setImageAlpha(image2);
-
-        switch (currentIntrinsic) {
-        case 0:
-            mBlend.forEachSrc(image1, image2);
-            break;
-        case 1:
-            mBlend.forEachDst(image1, image2);
-            break;
-        case 2:
-            mBlend.forEachSrcOver(image1, image2);
-            break;
-        case 3:
-            mBlend.forEachDstOver(image1, image2);
-            break;
-        case 4:
-            mBlend.forEachSrcIn(image1, image2);
-            break;
-        case 5:
-            mBlend.forEachDstIn(image1, image2);
-            break;
-        case 6:
-            mBlend.forEachSrcOut(image1, image2);
-            break;
-        case 7:
-            mBlend.forEachDstOut(image1, image2);
-            break;
-        case 8:
-            mBlend.forEachSrcAtop(image1, image2);
-            break;
-        case 9:
-            mBlend.forEachDstAtop(image1, image2);
-            break;
-        case 10:
-            mBlend.forEachXor(image1, image2);
-            break;
-        case 11:
-            mBlend.forEachAdd(image1, image2);
-            break;
-        case 12:
-            mBlend.forEachSubtract(image1, image2);
-            break;
-        case 13:
-            mBlend.forEachMultiply(image1, image2);
-            break;
-        }
-
-        mOutPixelsAllocation.copy2DRangeFrom(0, 0, image2.getType().getX(), image2.getType().getY(), image2, 0, 0);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25.java
deleted file mode 100644
index 0c6d41d..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.ScriptIntrinsicBlur;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Blur25 extends TestBase {
-    private boolean mUseIntrinsic = false;
-    private ScriptIntrinsicBlur mIntrinsic;
-
-    private int MAX_RADIUS = 25;
-    private ScriptC_threshold mScript;
-    private float mRadius = MAX_RADIUS;
-    private float mSaturation = 1.0f;
-    private Allocation mScratchPixelsAllocation1;
-    private Allocation mScratchPixelsAllocation2;
-
-
-    public Blur25(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Radius");
-        b.setProgress(100);
-        return true;
-    }
-
-
-    public void onBar1Changed(int progress) {
-        mRadius = ((float)progress) / 100.0f * MAX_RADIUS;
-        if (mRadius <= 0.10f) {
-            mRadius = 0.10f;
-        }
-        if (mUseIntrinsic) {
-            mIntrinsic.setRadius(mRadius);
-        } else {
-            mScript.invoke_setRadius((int)mRadius);
-        }
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setRadius(MAX_RADIUS);
-            mIntrinsic.setInput(mInPixelsAllocation);
-        } else {
-
-            Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
-            tb.setX(width);
-            tb.setY(height);
-            mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
-            mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
-
-            mScript = new ScriptC_threshold(mRS, res, R.raw.threshold);
-            mScript.set_width(width);
-            mScript.set_height(height);
-            mScript.invoke_setRadius(MAX_RADIUS);
-
-            mScript.set_InPixel(mInPixelsAllocation);
-            mScript.set_ScratchPixel1(mScratchPixelsAllocation1);
-            mScript.set_ScratchPixel2(mScratchPixelsAllocation2);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mOutPixelsAllocation);
-        } else {
-            mScript.forEach_copyIn(mInPixelsAllocation, mScratchPixelsAllocation1);
-            mScript.forEach_horz(mScratchPixelsAllocation2);
-            mScript.forEach_vert(mOutPixelsAllocation);
-        }
-    }
-
-    public void setupBenchmark() {
-        if (mUseIntrinsic) {
-            mIntrinsic.setRadius(MAX_RADIUS);
-        } else {
-            mScript.invoke_setRadius(MAX_RADIUS);
-        }
-    }
-
-    public void exitBenchmark() {
-        if (mUseIntrinsic) {
-            mIntrinsic.setRadius(mRadius);
-        } else {
-            mScript.invoke_setRadius((int)mRadius);
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25G.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25G.java
deleted file mode 100644
index ac0dad1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blur25G.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.graphics.Bitmap;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.ScriptIntrinsicBlur;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Blur25G extends TestBase {
-    private final int MAX_RADIUS = 25;
-    private float mRadius = MAX_RADIUS;
-
-    private ScriptIntrinsicBlur mIntrinsic;
-
-    private ScriptC_greyscale mScript;
-    private Allocation mScratchPixelsAllocation1;
-    private Allocation mScratchPixelsAllocation2;
-
-
-    public Blur25G() {
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Radius");
-        b.setProgress(100);
-        return true;
-    }
-
-
-    public void onBar1Changed(int progress) {
-        mRadius = ((float)progress) / 100.0f * MAX_RADIUS;
-        if (mRadius <= 0.10f) {
-            mRadius = 0.10f;
-        }
-        mIntrinsic.setRadius(mRadius);
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS));
-        tb.setX(width);
-        tb.setY(height);
-        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
-        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
-
-        mScript = new ScriptC_greyscale(mRS);
-        mScript.forEach_toU8(mInPixelsAllocation, mScratchPixelsAllocation1);
-
-        mIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8(mRS));
-        mIntrinsic.setRadius(MAX_RADIUS);
-        mIntrinsic.setInput(mScratchPixelsAllocation1);
-    }
-
-    public void runTest() {
-        mIntrinsic.forEach(mScratchPixelsAllocation2);
-    }
-
-    public void setupBenchmark() {
-        mIntrinsic.setRadius(MAX_RADIUS);
-    }
-
-    public void exitBenchmark() {
-        mIntrinsic.setRadius(mRadius);
-    }
-
-    public void updateBitmap(Bitmap b) {
-        mScript.forEach_toU8_4(mScratchPixelsAllocation2, mOutPixelsAllocation);
-        mOutPixelsAllocation.copyTo(b);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorCube.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorCube.java
deleted file mode 100644
index f313c46..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorCube.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.ScriptGroup;
-import android.renderscript.ScriptIntrinsic3DLUT;
-import android.renderscript.ScriptIntrinsicColorMatrix;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class ColorCube extends TestBase {
-    private Allocation mCube;
-    private ScriptC_colorcube mScript;
-    private ScriptIntrinsic3DLUT mIntrinsic;
-    private boolean mUseIntrinsic;
-
-    public ColorCube(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    private void initCube() {
-        final int sx = 32;
-        final int sy = 32;
-        final int sz = 16;
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8_4(mRS));
-        tb.setX(sx);
-        tb.setY(sy);
-        tb.setZ(sz);
-        Type t = tb.create();
-        mCube = Allocation.createTyped(mRS, t);
-
-        int dat[] = new int[sx * sy * sz];
-        for (int z = 0; z < sz; z++) {
-            for (int y = 0; y < sy; y++) {
-                for (int x = 0; x < sx; x++ ) {
-                    int v = 0xff000000;
-                    v |= (0xff * x / (sx - 1));
-                    v |= (0xff * y / (sy - 1)) << 8;
-                    v |= (0xff * z / (sz - 1)) << 16;
-                    dat[z*sy*sx + y*sx + x] = v;
-                }
-            }
-        }
-
-        mCube.copyFromUnchecked(dat);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_colorcube(mRS, res, R.raw.colorcube);
-        mIntrinsic = ScriptIntrinsic3DLUT.create(mRS, Element.U8_4(mRS));
-
-        initCube();
-        mScript.invoke_setCube(mCube);
-        mIntrinsic.setLUT(mCube);
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
deleted file mode 100644
index 2ac40a1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.ScriptGroup;
-import android.renderscript.ScriptIntrinsicColorMatrix;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class ColorMatrix extends TestBase {
-    private ScriptC_colormatrix mScript;
-    private ScriptIntrinsicColorMatrix mIntrinsic;
-    private boolean mUseIntrinsic;
-    private boolean mUseGrey;
-
-    public ColorMatrix(boolean useIntrinsic, boolean useGrey) {
-        mUseIntrinsic = useIntrinsic;
-        mUseGrey = useGrey;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        Matrix4f m = new Matrix4f();
-        m.set(1, 0, 0.2f);
-        m.set(1, 1, 0.9f);
-        m.set(1, 2, 0.2f);
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
-            if (mUseGrey) {
-                mIntrinsic.setGreyscale();
-            } else {
-                mIntrinsic.setColorMatrix(m);
-            }
-        } else {
-            mScript = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
-            mScript.invoke_setMatrix(m);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Contrast.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Contrast.java
deleted file mode 100644
index f3cf1b7..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Contrast.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-
-public class Contrast extends TestBase {
-    private ScriptC_contrast mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_contrast(mRS);
-    }
-
-    public void runTest() {
-        mScript.invoke_setBright(50.f);
-        mScript.forEach_contrast(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Convolve3x3.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Convolve3x3.java
deleted file mode 100644
index 18e9b43..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Convolve3x3.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.ScriptGroup;
-import android.renderscript.ScriptIntrinsicConvolve3x3;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Convolve3x3 extends TestBase {
-    private ScriptC_convolve3x3 mScript;
-    private ScriptIntrinsicConvolve3x3 mIntrinsic;
-
-    private int mWidth;
-    private int mHeight;
-    private boolean mUseIntrinsic;
-
-    public Convolve3x3(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        float f[] = new float[9];
-        f[0] =  0.f;    f[1] = -1.f;    f[2] =  0.f;
-        f[3] = -1.f;    f[4] =  5.f;    f[5] = -1.f;
-        f[6] =  0.f;    f[7] = -1.f;    f[8] =  0.f;
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setCoefficients(f);
-            mIntrinsic.setInput(mInPixelsAllocation);
-        } else {
-            mScript = new ScriptC_convolve3x3(mRS, res, R.raw.convolve3x3);
-            mScript.set_gCoeffs(f);
-            mScript.set_gIn(mInPixelsAllocation);
-            mScript.set_gWidth(mWidth);
-            mScript.set_gHeight(mHeight);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Convolve5x5.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Convolve5x5.java
deleted file mode 100644
index 03b3bb8..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Convolve5x5.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.ScriptGroup;
-import android.renderscript.ScriptIntrinsicConvolve5x5;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Convolve5x5 extends TestBase {
-    private ScriptC_convolve5x5 mScript;
-    private ScriptIntrinsicConvolve5x5 mIntrinsic;
-
-    private int mWidth;
-    private int mHeight;
-    private boolean mUseIntrinsic;
-
-    public Convolve5x5(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        float f[] = new float[25];
-        //f[0] = 0.012f; f[1] = 0.025f; f[2] = 0.031f; f[3] = 0.025f; f[4] = 0.012f;
-        //f[5] = 0.025f; f[6] = 0.057f; f[7] = 0.075f; f[8] = 0.057f; f[9] = 0.025f;
-        //f[10]= 0.031f; f[11]= 0.075f; f[12]= 0.095f; f[13]= 0.075f; f[14]= 0.031f;
-        //f[15]= 0.025f; f[16]= 0.057f; f[17]= 0.075f; f[18]= 0.057f; f[19]= 0.025f;
-        //f[20]= 0.012f; f[21]= 0.025f; f[22]= 0.031f; f[23]= 0.025f; f[24]= 0.012f;
-
-        //f[0] = 1.f; f[1] = 2.f; f[2] = 0.f; f[3] = -2.f; f[4] = -1.f;
-        //f[5] = 4.f; f[6] = 8.f; f[7] = 0.f; f[8] = -8.f; f[9] = -4.f;
-        //f[10]= 6.f; f[11]=12.f; f[12]= 0.f; f[13]=-12.f; f[14]= -6.f;
-        //f[15]= 4.f; f[16]= 8.f; f[17]= 0.f; f[18]= -8.f; f[19]= -4.f;
-        //f[20]= 1.f; f[21]= 2.f; f[22]= 0.f; f[23]= -2.f; f[24]= -1.f;
-
-        f[0] = -1.f; f[1] = -3.f; f[2] = -4.f; f[3] = -3.f; f[4] = -1.f;
-        f[5] = -3.f; f[6] =  0.f; f[7] =  6.f; f[8] =  0.f; f[9] = -3.f;
-        f[10]= -4.f; f[11]=  6.f; f[12]= 20.f; f[13]=  6.f; f[14]= -4.f;
-        f[15]= -3.f; f[16]=  0.f; f[17]=  6.f; f[18]=  0.f; f[19]= -3.f;
-        f[20]= -1.f; f[21]= -3.f; f[22]= -4.f; f[23]= -3.f; f[24]= -1.f;
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicConvolve5x5.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setCoefficients(f);
-            mIntrinsic.setInput(mInPixelsAllocation);
-        } else {
-            mScript = new ScriptC_convolve5x5(mRS, res, R.raw.convolve5x5);
-            mScript.set_gCoeffs(f);
-            mScript.set_gIn(mInPixelsAllocation);
-            mScript.set_gWidth(mWidth);
-            mScript.set_gHeight(mHeight);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Copy.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Copy.java
deleted file mode 100644
index efca0b5..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Copy.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Copy extends TestBase {
-    private ScriptC_copy mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_copy(mRS, res, R.raw.copy);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/CrossProcess.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/CrossProcess.java
deleted file mode 100644
index b9e3524..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/CrossProcess.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.ScriptIntrinsicLUT;
-import android.util.Log;
-
-public class CrossProcess extends TestBase {
-    private ScriptIntrinsicLUT mIntrinsic;
-
-    public void createTest(android.content.res.Resources res) {
-        mIntrinsic = ScriptIntrinsicLUT.create(mRS, Element.U8_4(mRS));
-        for (int ct=0; ct < 256; ct++) {
-            float f = ((float)ct) / 255.f;
-
-            float r = f;
-            if (r < 0.5f) {
-                r = 4.0f * r * r * r;
-            } else {
-                r = 1.0f - r;
-                r = 1.0f - (4.0f * r * r * r);
-            }
-            mIntrinsic.setRed(ct, (int)(r * 255.f + 0.5f));
-
-            float g = f;
-            if (g < 0.5f) {
-                g = 2.0f * g * g;
-            } else {
-                g = 1.0f - g;
-                g = 1.0f - (2.0f * g * g);
-            }
-            mIntrinsic.setGreen(ct, (int)(g * 255.f + 0.5f));
-
-            float b = f * 0.5f + 0.25f;
-            mIntrinsic.setBlue(ct, (int)(b * 255.f + 0.5f));
-        }
-
-    }
-
-    public void runTest() {
-        mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Exposure.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Exposure.java
deleted file mode 100644
index bec53ab..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Exposure.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-
-public class Exposure extends TestBase {
-    private ScriptC_exposure mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_exposure(mRS);
-    }
-
-    public void runTest() {
-        mScript.invoke_setBright(50.f);
-        mScript.forEach_exposure(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java
deleted file mode 100644
index 81868b10..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Sampler;
-import android.renderscript.Type;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Fisheye extends TestBase {
-    private ScriptC_fisheye_full mScript_full = null;
-    private ScriptC_fisheye_relaxed mScript_relaxed = null;
-    private ScriptC_fisheye_approx_full mScript_approx_full = null;
-    private ScriptC_fisheye_approx_relaxed mScript_approx_relaxed = null;
-    private final boolean approx;
-    private final boolean relaxed;
-    private float center_x = 0.5f;
-    private float center_y = 0.5f;
-    private float scale = 0.5f;
-
-    public Fisheye(boolean approx, boolean relaxed) {
-        this.approx = approx;
-        this.relaxed = relaxed;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Scale");
-        b.setMax(100);
-        b.setProgress(25);
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Shift center X");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Shift center Y");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        scale = progress / 50.0f;
-        do_init();
-    }
-    public void onBar2Changed(int progress) {
-        center_x = progress / 100.0f;
-        do_init();
-    }
-    public void onBar3Changed(int progress) {
-        center_y = progress / 100.0f;
-        do_init();
-    }
-
-    private void do_init() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.invoke_init_filter(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale);
-            else
-                mScript_approx_full.invoke_init_filter(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale);
-        } else if (relaxed)
-            mScript_relaxed.invoke_init_filter(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale);
-        else
-            mScript_full.invoke_init_filter(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        if (approx) {
-            if (relaxed) {
-                mScript_approx_relaxed = new ScriptC_fisheye_approx_relaxed(mRS,
-                        res, R.raw.fisheye_approx_relaxed);
-                mScript_approx_relaxed.set_in_alloc(mInPixelsAllocation);
-                mScript_approx_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-            } else {
-                mScript_approx_full = new ScriptC_fisheye_approx_full(mRS, res,
-                        R.raw.fisheye_approx_full);
-                mScript_approx_full.set_in_alloc(mInPixelsAllocation);
-                mScript_approx_full.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-            }
-        } else if (relaxed) {
-            mScript_relaxed = new ScriptC_fisheye_relaxed(mRS, res,
-                    R.raw.fisheye_relaxed);
-            mScript_relaxed.set_in_alloc(mInPixelsAllocation);
-            mScript_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-        } else {
-            mScript_full = new ScriptC_fisheye_full(mRS, res,
-                    R.raw.fisheye_full);
-            mScript_full.set_in_alloc(mInPixelsAllocation);
-            mScript_full.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-        }
-        do_init();
-    }
-
-    public void runTest() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.forEach_root(mOutPixelsAllocation);
-            else
-                mScript_approx_full.forEach_root(mOutPixelsAllocation);
-        } else if (relaxed)
-            mScript_relaxed.forEach_root(mOutPixelsAllocation);
-        else
-            mScript_full.forEach_root(mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java
deleted file mode 100644
index 8618cc8..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Grain extends TestBase {
-    private ScriptC_grain mScript;
-    private Allocation mNoise;
-    private Allocation mNoise2;
-
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Strength");
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        float s = progress / 100.0f;
-        mScript.set_gNoiseStrength(s);
-    }
-
-    private int findHighBit(int v) {
-        int bit = 0;
-        while (v > 1) {
-            bit++;
-            v >>= 1;
-        }
-        return bit;
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        int noiseW = findHighBit(width);
-        int noiseH = findHighBit(height);
-        if (noiseW > 9) {
-            noiseW = 9;
-        }
-        if (noiseH > 9) {
-            noiseH = 9;
-        }
-        noiseW = 1 << noiseW;
-        noiseH = 1 << noiseH;
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS));
-        tb.setX(noiseW);
-        tb.setY(noiseH);
-        mNoise = Allocation.createTyped(mRS, tb.create());
-        mNoise2 = Allocation.createTyped(mRS, tb.create());
-
-        mScript = new ScriptC_grain(mRS, res, R.raw.grain);
-        mScript.set_gWMask(noiseW - 1);
-        mScript.set_gHMask(noiseH - 1);
-        mScript.set_gNoiseStrength(0.5f);
-        mScript.set_gBlendSource(mNoise);
-        mScript.set_gNoise(mNoise2);
-    }
-
-    public void runTest() {
-        mScript.forEach_genRand(mNoise);
-        mScript.forEach_blend9(mNoise2);
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Greyscale.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Greyscale.java
deleted file mode 100644
index 3db210a..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Greyscale.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Greyscale extends TestBase {
-    private ScriptC_greyscale mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_greyscale(mRS, res, R.raw.greyscale);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java
deleted file mode 100644
index 29c204c..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.ScriptIntrinsicConvolve3x3;
-import android.renderscript.ScriptIntrinsicColorMatrix;
-import android.renderscript.Type;
-import android.renderscript.Matrix4f;
-import android.renderscript.ScriptGroup;
-import android.util.Log;
-
-public class GroupTest extends TestBase {
-    private ScriptIntrinsicConvolve3x3 mConvolve;
-    private ScriptIntrinsicColorMatrix mMatrix;
-
-    private Allocation mScratchPixelsAllocation1;
-    private ScriptGroup mGroup;
-
-    private int mWidth;
-    private int mHeight;
-    private boolean mUseNative;
-
-
-    public GroupTest(boolean useNative) {
-        mUseNative = useNative;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        mConvolve = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS));
-        mMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
-
-        float f[] = new float[9];
-        f[0] =  0.f;    f[1] = -1.f;    f[2] =  0.f;
-        f[3] = -1.f;    f[4] =  5.f;    f[5] = -1.f;
-        f[6] =  0.f;    f[7] = -1.f;    f[8] =  0.f;
-        mConvolve.setCoefficients(f);
-
-        Matrix4f m = new Matrix4f();
-        m.set(1, 0, 0.2f);
-        m.set(1, 1, 0.9f);
-        m.set(1, 2, 0.2f);
-        mMatrix.setColorMatrix(m);
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8_4(mRS));
-        tb.setX(mWidth);
-        tb.setY(mHeight);
-        Type connect = tb.create();
-
-        if (mUseNative) {
-            ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
-            b.addKernel(mConvolve.getKernelID());
-            b.addKernel(mMatrix.getKernelID());
-            b.addConnection(connect, mConvolve.getKernelID(), mMatrix.getKernelID());
-            mGroup = b.create();
-        } else {
-            mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect);
-        }
-    }
-
-    public void runTest() {
-        mConvolve.setInput(mInPixelsAllocation);
-        if (mUseNative) {
-            mGroup.setOutput(mMatrix.getKernelID(), mOutPixelsAllocation);
-            mGroup.execute();
-        } else {
-            mConvolve.forEach(mScratchPixelsAllocation1);
-            mMatrix.forEach(mScratchPixelsAllocation1, mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
deleted file mode 100644
index d2139ea..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.view.SurfaceView;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.view.View;
-import android.util.Log;
-import android.renderscript.ScriptC;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Script;
-
-import android.os.Environment;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-public class ImageProcessingActivity extends Activity
-                                       implements SeekBar.OnSeekBarChangeListener {
-    private final String TAG = "Img";
-    public final String RESULT_FILE = "image_processing_result.csv";
-
-    RenderScript mRS;
-    Allocation mInPixelsAllocation;
-    Allocation mInPixelsAllocation2;
-    Allocation mOutPixelsAllocation;
-
-    /**
-     * Define enum type for test names
-     */
-    public enum TestName {
-        // totally there are 38 test cases
-        LEVELS_VEC3_RELAXED ("Levels Vec3 Relaxed"),
-        LEVELS_VEC4_RELAXED ("Levels Vec4 Relaxed"),
-        LEVELS_VEC3_FULL ("Levels Vec3 Full"),
-        LEVELS_VEC4_FULL ("Levels Vec4 Full"),
-        BLUR_RADIUS_25 ("Blur radius 25"),
-        INTRINSIC_BLUE_RADIUS_25 ("Intrinsic Blur radius 25"),
-        GREYSCALE ("Greyscale"),
-        GRAIN ("Grain"),
-        FISHEYE_FULL ("Fisheye Full"),
-        FISHEYE_RELAXED ("Fisheye Relaxed"),
-        FISHEYE_APPROXIMATE_FULL ("Fisheye Approximate Full"),
-        FISHEYE_APPROXIMATE_RELAXED ("Fisheye Approximate Relaxed"),
-        VIGNETTE_FULL ("Vignette Full"),
-        VIGNETTE_RELAXED ("Vignette Relaxed"),
-        VIGNETTE_APPROXIMATE_FULL ("Vignette Approximate Full"),
-        VIGNETTE_APPROXIMATE_RELAXED ("Vignette Approximate Relaxed"),
-        GROUP_TEST_EMULATED ("Group Test (emulated)"),
-        GROUP_TEST_NATIVE ("Group Test (native)"),
-        CONVOLVE_3X3 ("Convolve 3x3"),
-        INTRINSICS_CONVOLVE_3X3 ("Intrinsics Convolve 3x3"),
-        COLOR_MATRIX ("ColorMatrix"),
-        INTRINSICS_COLOR_MATRIX ("Intrinsics ColorMatrix"),
-        INTRINSICS_COLOR_MATRIX_GREY ("Intrinsics ColorMatrix Grey"),
-        COPY ("Copy"),
-        CROSS_PROCESS_USING_LUT ("CrossProcess (using LUT)"),
-        CONVOLVE_5X5 ("Convolve 5x5"),
-        INTRINSICS_CONVOLVE_5X5 ("Intrinsics Convolve 5x5"),
-        MANDELBROT ("Mandelbrot"),
-        INTRINSICS_BLEND ("Intrinsics Blend"),
-        INTRINSICS_BLUR_25G ("Intrinsics Blur 25 uchar"),
-        VIBRANCE ("Vibrance"),
-        BW_FILTER ("BW Filter"),
-        SHADOWS ("Shadows"),
-        CONTRAST ("Contrast"),
-        EXPOSURE ("Exposure"),
-        WHITE_BALANCE ("White Balance"),
-        COLOR_CUBE ("Color Cube"),
-        COLOR_CUBE_3D_INTRINSIC ("Color Cube (3D LUT intrinsic)"),
-        USAGE_IO ("Usage io)");
-
-
-        private final String name;
-
-        private TestName(String s) {
-            name = s;
-        }
-
-        // return quoted string as displayed test name
-        public String toString() {
-            return name;
-        }
-    }
-
-    Bitmap mBitmapIn;
-    Bitmap mBitmapIn2;
-    Bitmap mBitmapOut;
-
-    private Spinner mSpinner;
-    private SeekBar mBar1;
-    private SeekBar mBar2;
-    private SeekBar mBar3;
-    private SeekBar mBar4;
-    private SeekBar mBar5;
-    private TextView mText1;
-    private TextView mText2;
-    private TextView mText3;
-    private TextView mText4;
-    private TextView mText5;
-
-    private float mSaturation = 1.0f;
-
-    private TextView mBenchmarkResult;
-    private Spinner mTestSpinner;
-
-    private SurfaceView mSurfaceView;
-    private ImageView mDisplayView;
-
-    private boolean mDoingBenchmark;
-
-    private TestBase mTest;
-    private int mRunCount;
-
-    public void updateDisplay() {
-        mHandler.sendMessage(Message.obtain());
-    }
-
-    private Handler mHandler = new Handler() {
-        // Allow the filter to complete without blocking the UI
-        // thread.  When the message arrives that the op is complete
-        // we will either mark completion or start a new filter if
-        // more work is ready.  Either way, display the result.
-        @Override
-        public void handleMessage(Message msg) {
-            mTest.updateBitmap(mBitmapOut);
-            mDisplayView.invalidate();
-
-            boolean doTest = false;
-            synchronized(this) {
-                if (mRunCount > 0) {
-                    mRunCount--;
-                    if (mRunCount > 0) {
-                        doTest = true;
-                    }
-                }
-            }
-            if (doTest) {
-                mTest.runTestSendMessage();
-            }
-        }
-
-    };
-
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        if (fromUser) {
-
-            if (seekBar == mBar1) {
-                mTest.onBar1Changed(progress);
-            } else if (seekBar == mBar2) {
-                mTest.onBar2Changed(progress);
-            } else if (seekBar == mBar3) {
-                mTest.onBar3Changed(progress);
-            } else if (seekBar == mBar4) {
-                mTest.onBar4Changed(progress);
-            } else if (seekBar == mBar5) {
-                mTest.onBar5Changed(progress);
-            }
-
-            boolean doTest = false;
-            synchronized(this) {
-                if (mRunCount == 0) {
-                    doTest = true;
-                    mRunCount = 1;
-                } else {
-                    mRunCount = 2;
-                }
-            }
-            if (doTest) {
-                mTest.runTestSendMessage();
-            }
-        }
-    }
-
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-    }
-
-    void setupBars() {
-        mSpinner.setVisibility(View.VISIBLE);
-        mTest.onSpinner1Setup(mSpinner);
-
-        mBar1.setVisibility(View.VISIBLE);
-        mText1.setVisibility(View.VISIBLE);
-        mTest.onBar1Setup(mBar1, mText1);
-
-        mBar2.setVisibility(View.VISIBLE);
-        mText2.setVisibility(View.VISIBLE);
-        mTest.onBar2Setup(mBar2, mText2);
-
-        mBar3.setVisibility(View.VISIBLE);
-        mText3.setVisibility(View.VISIBLE);
-        mTest.onBar3Setup(mBar3, mText3);
-
-        mBar4.setVisibility(View.VISIBLE);
-        mText4.setVisibility(View.VISIBLE);
-        mTest.onBar4Setup(mBar4, mText4);
-
-        mBar5.setVisibility(View.VISIBLE);
-        mText5.setVisibility(View.VISIBLE);
-        mTest.onBar5Setup(mBar5, mText5);
-    }
-
-
-    void changeTest(TestName testName) {
-        if (mTest != null) {
-            mTest.destroy();
-        }
-        switch(testName) {
-        case LEVELS_VEC3_RELAXED:
-            mTest = new LevelsV4(false, false);
-            break;
-        case LEVELS_VEC4_RELAXED:
-            mTest = new LevelsV4(false, true);
-            break;
-        case LEVELS_VEC3_FULL:
-            mTest = new LevelsV4(true, false);
-            break;
-        case LEVELS_VEC4_FULL:
-            mTest = new LevelsV4(true, true);
-            break;
-        case BLUR_RADIUS_25:
-            mTest = new Blur25(false);
-            break;
-        case INTRINSIC_BLUE_RADIUS_25:
-            mTest = new Blur25(true);
-            break;
-        case GREYSCALE:
-            mTest = new Greyscale();
-            break;
-        case GRAIN:
-            mTest = new Grain();
-            break;
-        case FISHEYE_FULL:
-            mTest = new Fisheye(false, false);
-            break;
-        case FISHEYE_RELAXED:
-            mTest = new Fisheye(false, true);
-            break;
-        case FISHEYE_APPROXIMATE_FULL:
-            mTest = new Fisheye(true, false);
-            break;
-        case FISHEYE_APPROXIMATE_RELAXED:
-            mTest = new Fisheye(true, true);
-            break;
-        case VIGNETTE_FULL:
-            mTest = new Vignette(false, false);
-            break;
-        case VIGNETTE_RELAXED:
-            mTest = new Vignette(false, true);
-            break;
-        case VIGNETTE_APPROXIMATE_FULL:
-            mTest = new Vignette(true, false);
-            break;
-        case VIGNETTE_APPROXIMATE_RELAXED:
-            mTest = new Vignette(true, true);
-            break;
-        case GROUP_TEST_EMULATED:
-            mTest = new GroupTest(false);
-            break;
-        case GROUP_TEST_NATIVE:
-            mTest = new GroupTest(true);
-            break;
-        case CONVOLVE_3X3:
-            mTest = new Convolve3x3(false);
-            break;
-        case INTRINSICS_CONVOLVE_3X3:
-            mTest = new Convolve3x3(true);
-            break;
-        case COLOR_MATRIX:
-            mTest = new ColorMatrix(false, false);
-            break;
-        case INTRINSICS_COLOR_MATRIX:
-            mTest = new ColorMatrix(true, false);
-            break;
-        case INTRINSICS_COLOR_MATRIX_GREY:
-            mTest = new ColorMatrix(true, true);
-            break;
-        case COPY:
-            mTest = new Copy();
-            break;
-        case CROSS_PROCESS_USING_LUT:
-            mTest = new CrossProcess();
-            break;
-        case CONVOLVE_5X5:
-            mTest = new Convolve5x5(false);
-            break;
-        case INTRINSICS_CONVOLVE_5X5:
-            mTest = new Convolve5x5(true);
-            break;
-        case MANDELBROT:
-            mTest = new Mandelbrot();
-            break;
-        case INTRINSICS_BLEND:
-            mTest = new Blend();
-            break;
-        case INTRINSICS_BLUR_25G:
-            mTest = new Blur25G();
-            break;
-        case VIBRANCE:
-            mTest = new Vibrance();
-            break;
-        case BW_FILTER:
-            mTest = new BWFilter();
-            break;
-        case SHADOWS:
-            mTest = new Shadows();
-            break;
-        case CONTRAST:
-            mTest = new Contrast();
-            break;
-        case EXPOSURE:
-            mTest = new Exposure();
-            break;
-        case WHITE_BALANCE:
-            mTest = new WhiteBalance();
-            break;
-        case COLOR_CUBE:
-            mTest = new ColorCube(false);
-            break;
-        case COLOR_CUBE_3D_INTRINSIC:
-            mTest = new ColorCube(true);
-            break;
-        case USAGE_IO:
-            mTest = new UsageIO();
-            break;
-        }
-
-        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2, mBitmapOut);
-        setupBars();
-
-        mTest.runTest();
-        updateDisplay();
-        mBenchmarkResult.setText("Result: not run");
-    }
-
-    void setupTests() {
-        mTestSpinner.setAdapter(new ArrayAdapter<TestName>(
-            this, R.layout.spinner_layout, TestName.values()));
-    }
-
-    private AdapterView.OnItemSelectedListener mTestSpinnerListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-                    changeTest(TestName.values()[pos]);
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-            };
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        mBitmapIn = loadBitmap(R.drawable.img1600x1067);
-        mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b);
-        mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
-                                         mBitmapIn.getConfig());
-
-        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
-
-        mDisplayView = (ImageView) findViewById(R.id.display);
-        mDisplayView.setImageBitmap(mBitmapOut);
-
-        mSpinner = (Spinner) findViewById(R.id.spinner1);
-
-        mBar1 = (SeekBar) findViewById(R.id.slider1);
-        mBar2 = (SeekBar) findViewById(R.id.slider2);
-        mBar3 = (SeekBar) findViewById(R.id.slider3);
-        mBar4 = (SeekBar) findViewById(R.id.slider4);
-        mBar5 = (SeekBar) findViewById(R.id.slider5);
-
-        mBar1.setOnSeekBarChangeListener(this);
-        mBar2.setOnSeekBarChangeListener(this);
-        mBar3.setOnSeekBarChangeListener(this);
-        mBar4.setOnSeekBarChangeListener(this);
-        mBar5.setOnSeekBarChangeListener(this);
-
-        mText1 = (TextView) findViewById(R.id.slider1Text);
-        mText2 = (TextView) findViewById(R.id.slider2Text);
-        mText3 = (TextView) findViewById(R.id.slider3Text);
-        mText4 = (TextView) findViewById(R.id.slider4Text);
-        mText5 = (TextView) findViewById(R.id.slider5Text);
-
-        mTestSpinner = (Spinner) findViewById(R.id.filterselection);
-        mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
-
-        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
-        mBenchmarkResult.setText("Result: not run");
-
-
-        mRS = RenderScript.create(this);
-        mInPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
-        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, mBitmapIn2);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, mBitmapOut);
-
-
-        setupTests();
-        changeTest(TestName.LEVELS_VEC3_RELAXED);
-    }
-
-
-    private Bitmap loadBitmap(int resource) {
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        return BitmapFactory.decodeResource(getResources(), resource, options);
-    }
-
-    // button hook
-    public void benchmark(View v) {
-        float t = getBenchmark();
-        //long javaTime = javaFilter();
-        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
-        mBenchmarkResult.setText("Result: " + t + " ms");
-        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
-    }
-
-    public void benchmark_all(View v) {
-        // write result into a file
-        File externalStorage = Environment.getExternalStorageDirectory();
-        if (!externalStorage.canWrite()) {
-            Log.v(TAG, "sdcard is not writable");
-            return;
-        }
-        File resultFile = new File(externalStorage, RESULT_FILE);
-        resultFile.setWritable(true, false);
-        try {
-            BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile));
-            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
-            for (TestName tn: TestName.values()) {
-                changeTest(tn);
-                float t = getBenchmark();
-                String s = new String("" + tn.toString() + ", " + t);
-                rsWriter.write(s + "\n");
-                Log.v(TAG, "Test " + s + "ms\n");
-            }
-            rsWriter.close();
-        } catch (IOException e) {
-            Log.v(TAG, "Unable to write result file " + e.getMessage());
-        }
-        changeTest(TestName.LEVELS_VEC3_RELAXED);
-    }
-
-    // For benchmark test
-    public float getBenchmark() {
-        mDoingBenchmark = true;
-
-        mTest.setupBenchmark();
-        long result = 0;
-
-        //Log.v(TAG, "Warming");
-        long t = java.lang.System.currentTimeMillis() + 250;
-        do {
-            mTest.runTest();
-            mTest.finish();
-        } while (t > java.lang.System.currentTimeMillis());
-
-        //Log.v(TAG, "Benchmarking");
-        int ct = 0;
-        t = java.lang.System.currentTimeMillis();
-        do {
-            mTest.runTest();
-            mTest.finish();
-            ct++;
-        } while ((t+1000) > java.lang.System.currentTimeMillis());
-        t = java.lang.System.currentTimeMillis() - t;
-        float ft = (float)t;
-        ft /= ct;
-
-        mTest.exitBenchmark();
-        mDoingBenchmark = false;
-
-        return ft;
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
deleted file mode 100644
index 5263c61..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.image;
-
-import com.android.rs.image.ImageProcessingTestRunner;
-
-import android.os.Bundle;
-import com.android.rs.image.ImageProcessingActivity.TestName;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-
-/**
- * ImageProcessing benchmark test.
- * To run the test, please use command
- *
- * adb shell am instrument -e iteration <n> -w com.android.rs.image/.ImageProcessingTestRunner
- *
- */
-public class ImageProcessingTest extends ActivityInstrumentationTestCase2<ImageProcessingActivity> {
-    private final String TAG = "ImageProcessingTest";
-    private final String TEST_NAME = "Testname";
-    private final String ITERATIONS = "Iterations";
-    private final String BENCHMARK = "Benchmark";
-    private static int INSTRUMENTATION_IN_PROGRESS = 2;
-    private int mIteration;
-    private ImageProcessingActivity mActivity;
-
-    public ImageProcessingTest() {
-        super(ImageProcessingActivity.class);
-    }
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        setActivityInitialTouchMode(false);
-        mActivity = getActivity();
-        ImageProcessingTestRunner mRunner = (ImageProcessingTestRunner) getInstrumentation();
-        mIteration = mRunner.mIteration;
-        assertTrue("please enter a valid iteration value", mIteration > 0);
-   }
-
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    class TestAction implements Runnable {
-        TestName mTestName;
-        float mResult;
-        public TestAction(TestName testName) {
-            mTestName = testName;
-        }
-        public void run() {
-            mActivity.changeTest(mTestName);
-            mResult = mActivity.getBenchmark();
-            Log.v(TAG, "Benchmark for test \"" + mTestName.toString() + "\" is: " + mResult);
-            synchronized(this) {
-                this.notify();
-            }
-        }
-        public float getBenchmark() {
-            return mResult;
-        }
-    }
-
-    // Set the benchmark thread to run on ui thread
-    // Synchronized the thread such that the test will wait for the benchmark thread to finish
-    public void runOnUiThread(Runnable action) {
-        synchronized(action) {
-            mActivity.runOnUiThread(action);
-            try {
-                action.wait();
-            } catch (InterruptedException e) {
-                Log.v(TAG, "waiting for action running on UI thread is interrupted: " +
-                        e.toString());
-            }
-        }
-    }
-
-    public void runTest(TestAction ta, String testName) {
-        float sum = 0;
-        for (int i = 0; i < mIteration; i++) {
-            runOnUiThread(ta);
-            float bmValue = ta.getBenchmark();
-            Log.v(TAG, "results for iteration " + i + " is " + bmValue);
-            sum += bmValue;
-        }
-        float avgResult = sum/mIteration;
-
-        // post result to INSTRUMENTATION_STATUS
-        Bundle results = new Bundle();
-        results.putString(TEST_NAME, testName);
-        results.putInt(ITERATIONS, mIteration);
-        results.putFloat(BENCHMARK, avgResult);
-        getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
-    }
-
-    // Test case 0: Levels Vec3 Relaxed
-    @LargeTest
-    public void testLevelsVec3Relaxed() {
-        TestAction ta = new TestAction(TestName.LEVELS_VEC3_RELAXED);
-        runTest(ta, TestName.LEVELS_VEC3_RELAXED.name());
-    }
-
-    // Test case 1: Levels Vec4 Relaxed
-    @LargeTest
-    public void testLevelsVec4Relaxed() {
-        TestAction ta = new TestAction(TestName.LEVELS_VEC4_RELAXED);
-        runTest(ta, TestName.LEVELS_VEC4_RELAXED.name());
-    }
-
-    // Test case 2: Levels Vec3 Full
-    @LargeTest
-    public void testLevelsVec3Full() {
-        TestAction ta = new TestAction(TestName.LEVELS_VEC3_FULL);
-        runTest(ta, TestName.LEVELS_VEC3_FULL.name());
-    }
-
-    // Test case 3: Levels Vec4 Full
-    @LargeTest
-    public void testLevelsVec4Full() {
-        TestAction ta = new TestAction(TestName.LEVELS_VEC4_FULL);
-        runTest(ta, TestName.LEVELS_VEC4_FULL.name());
-    }
-
-    // Test case 4: Blur Radius 25
-    @LargeTest
-    public void testBlurRadius25() {
-        TestAction ta = new TestAction(TestName.BLUR_RADIUS_25);
-        runTest(ta, TestName.BLUR_RADIUS_25.name());
-    }
-
-    // Test case 5: Intrinsic Blur Radius 25
-    @LargeTest
-    public void testIntrinsicBlurRadius25() {
-        TestAction ta = new TestAction(TestName.INTRINSIC_BLUE_RADIUS_25);
-        runTest(ta, TestName.INTRINSIC_BLUE_RADIUS_25.name());
-    }
-
-    // Test case 6: Greyscale
-    @LargeTest
-    public void testGreyscale() {
-        TestAction ta = new TestAction(TestName.GREYSCALE);
-        runTest(ta, TestName.GREYSCALE.name());
-    }
-
-    // Test case 7: Grain
-    @LargeTest
-    public void testGrain() {
-        TestAction ta = new TestAction(TestName.GRAIN);
-        runTest(ta, TestName.GRAIN.name());
-    }
-
-    // Test case 8: Fisheye Full
-    @LargeTest
-    public void testFisheyeFull() {
-        TestAction ta = new TestAction(TestName.FISHEYE_FULL);
-        runTest(ta, TestName.FISHEYE_FULL.name());
-    }
-
-    // Test case 9: Fisheye Relaxed
-    @LargeTest
-    public void testFishEyeRelaxed() {
-        TestAction ta = new TestAction(TestName.FISHEYE_RELAXED);
-        runTest(ta, TestName.FISHEYE_RELAXED.name());
-    }
-
-    // Test case 10: Fisheye Approximate Full
-    @LargeTest
-    public void testFisheyeApproximateFull() {
-        TestAction ta = new TestAction(TestName.FISHEYE_APPROXIMATE_FULL);
-        runTest(ta, TestName.FISHEYE_APPROXIMATE_FULL.name());
-    }
-
-    // Test case 11: Fisheye Approximate Relaxed
-    @LargeTest
-    public void testFisheyeApproximateRelaxed() {
-        TestAction ta = new TestAction(TestName.FISHEYE_APPROXIMATE_RELAXED);
-        runTest(ta, TestName.FISHEYE_APPROXIMATE_RELAXED.name());
-    }
-
-    // Test case 12: Vignette Full
-    @LargeTest
-    public void testVignetteFull() {
-        TestAction ta = new TestAction(TestName.VIGNETTE_FULL);
-        runTest(ta, TestName.VIGNETTE_FULL.name());
-    }
-
-    // Test case 13: Vignette Relaxed
-    @LargeTest
-    public void testVignetteRelaxed() {
-        TestAction ta = new TestAction(TestName.VIGNETTE_RELAXED);
-        runTest(ta, TestName.VIGNETTE_RELAXED.name());
-    }
-
-    // Test case 14: Vignette Approximate Full
-    @LargeTest
-    public void testVignetteApproximateFull() {
-        TestAction ta = new TestAction(TestName.VIGNETTE_APPROXIMATE_FULL);
-        runTest(ta, TestName.VIGNETTE_APPROXIMATE_FULL.name());
-    }
-
-    // Test case 15: Vignette Approximate Relaxed
-    @LargeTest
-    public void testVignetteApproximateRelaxed() {
-        TestAction ta = new TestAction(TestName.VIGNETTE_APPROXIMATE_RELAXED);
-        runTest(ta, TestName.VIGNETTE_APPROXIMATE_RELAXED.name());
-    }
-
-    // Test case 16: Group Test (emulated)
-    @LargeTest
-    public void testGroupTestEmulated() {
-        TestAction ta = new TestAction(TestName.GROUP_TEST_EMULATED);
-        runTest(ta, TestName.GROUP_TEST_EMULATED.name());
-    }
-
-    // Test case 17: Group Test (native)
-    @LargeTest
-    public void testGroupTestNative() {
-        TestAction ta = new TestAction(TestName.GROUP_TEST_NATIVE);
-        runTest(ta, TestName.GROUP_TEST_NATIVE.name());
-    }
-
-    // Test case 18: Convolve 3x3
-    @LargeTest
-    public void testConvolve3x3() {
-        TestAction ta = new TestAction(TestName.CONVOLVE_3X3);
-        runTest(ta, TestName.CONVOLVE_3X3.name());
-    }
-
-    // Test case 19: Intrinsics Convolve 3x3
-    @LargeTest
-    public void testIntrinsicsConvolve3x3() {
-        TestAction ta = new TestAction(TestName.INTRINSICS_CONVOLVE_3X3);
-        runTest(ta, TestName.INTRINSICS_CONVOLVE_3X3.name());
-    }
-
-    // Test case 20: ColorMatrix
-    @LargeTest
-    public void testColorMatrix() {
-        TestAction ta = new TestAction(TestName.COLOR_MATRIX);
-        runTest(ta, TestName.COLOR_MATRIX.name());
-    }
-
-    // Test case 21: Intrinsics ColorMatrix
-    @LargeTest
-    public void testIntrinsicsColorMatrix() {
-        TestAction ta = new TestAction(TestName.INTRINSICS_COLOR_MATRIX);
-        runTest(ta, TestName.INTRINSICS_COLOR_MATRIX.name());
-    }
-
-    // Test case 22: Intrinsics ColorMatrix Grey
-    @LargeTest
-    public void testIntrinsicsColorMatrixGrey() {
-        TestAction ta = new TestAction(TestName.INTRINSICS_COLOR_MATRIX_GREY);
-        runTest(ta, TestName.INTRINSICS_COLOR_MATRIX_GREY.name());
-    }
-
-    // Test case 23: Copy
-    @LargeTest
-    public void testCopy() {
-        TestAction ta = new TestAction(TestName.COPY);
-        runTest(ta, TestName.COPY.name());
-    }
-
-    // Test case 24: CrossProcess (using LUT)
-    @LargeTest
-    public void testCrossProcessUsingLUT() {
-        TestAction ta = new TestAction(TestName.CROSS_PROCESS_USING_LUT);
-        runTest(ta, TestName.CROSS_PROCESS_USING_LUT.name());
-    }
-
-    // Test case 25: Convolve 5x5
-    @LargeTest
-    public void testConvolve5x5() {
-        TestAction ta = new TestAction(TestName.CONVOLVE_5X5);
-        runTest(ta, TestName.CONVOLVE_5X5.name());
-    }
-
-    // Test case 26: Intrinsics Convolve 5x5
-    @LargeTest
-    public void testIntrinsicsConvolve5x5() {
-        TestAction ta = new TestAction(TestName.INTRINSICS_CONVOLVE_5X5);
-        runTest(ta, TestName.INTRINSICS_CONVOLVE_5X5.name());
-    }
-
-    // Test case 27: Mandelbrot
-    @LargeTest
-    public void testMandelbrot() {
-        TestAction ta = new TestAction(TestName.MANDELBROT);
-        runTest(ta, TestName.MANDELBROT.name());
-    }
-
-    // Test case 28: Intrinsics Blend
-    @LargeTest
-    public void testIntrinsicsBlend() {
-        TestAction ta = new TestAction(TestName.INTRINSICS_BLEND);
-        runTest(ta, TestName.INTRINSICS_BLEND.name());
-    }
-
-    // Test case 29: Intrinsics Blur 25 uchar
-    @LargeTest
-    public void testIntrinsicsBlur25G() {
-        TestAction ta = new TestAction(TestName.INTRINSICS_BLUR_25G);
-        runTest(ta, TestName.INTRINSICS_BLUR_25G.name());
-    }
-
-    // Test case 30: Vibrance
-    @LargeTest
-    public void testVibrance() {
-        TestAction ta = new TestAction(TestName.VIBRANCE);
-        runTest(ta, TestName.VIBRANCE.name());
-    }
-
-    // Test case 31: BWFilter
-    @LargeTest
-    public void testBWFilter() {
-        TestAction ta = new TestAction(TestName.BW_FILTER);
-        runTest(ta, TestName.BW_FILTER.name());
-    }
-
-    // Test case 32: Shadows
-    @LargeTest
-    public void testShadows() {
-        TestAction ta = new TestAction(TestName.SHADOWS);
-        runTest(ta, TestName.SHADOWS.name());
-    }
-
-    // Test case 33: Contrast
-    @LargeTest
-    public void testContrast() {
-        TestAction ta = new TestAction(TestName.CONTRAST);
-        runTest(ta, TestName.CONTRAST.name());
-    }
-
-    // Test case 34: Exposure
-    @LargeTest
-    public void testExposure(){
-        TestAction ta = new TestAction(TestName.EXPOSURE);
-        runTest(ta, TestName.EXPOSURE.name());
-    }
-
-    // Test case 35: White Balance
-    @LargeTest
-    public void testWhiteBalance() {
-        TestAction ta = new TestAction(TestName.WHITE_BALANCE);
-        runTest(ta, TestName.WHITE_BALANCE.name());
-    }
-
-    // Test case 36: Color Cube
-    @LargeTest
-    public void testColorCube() {
-        TestAction ta = new TestAction(TestName.COLOR_CUBE);
-        runTest(ta, TestName.COLOR_CUBE.name());
-    }
-
-    // Test case 37: Color Cube (3D Intrinsic)
-    @LargeTest
-    public void testColorCube3DIntrinsic() {
-        TestAction ta = new TestAction(TestName.COLOR_CUBE_3D_INTRINSIC);
-        runTest(ta, TestName.COLOR_CUBE_3D_INTRINSIC.name());
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java
deleted file mode 100644
index 36fbb3e..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTestRunner.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.image;
-
-import com.android.rs.image.ImageProcessingTest;
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-import junit.framework.TestSuite;
-
-/**
- * Run the ImageProcessing benchmark test
- * adb shell am instrument -e iteration <n> -w com.android.rs.image/.ImageProcessingTestRunner
- *
- */
-public class ImageProcessingTestRunner extends InstrumentationTestRunner {
-    public int mIteration = 5;
-
-    @Override
-    public TestSuite getAllTests() {
-        TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(ImageProcessingTest.class);
-        return suite;
-    }
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        String strIteration = (String) icicle.get("iteration");
-        if (strIteration != null) {
-            mIteration = Integer.parseInt(strIteration);
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/LevelsV4.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/LevelsV4.java
deleted file mode 100644
index 9eb5647..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/LevelsV4.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Matrix3f;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-
-public class LevelsV4 extends TestBase {
-    private ScriptC_levels_relaxed mScriptR;
-    private ScriptC_levels_full mScriptF;
-    private float mInBlack = 0.0f;
-    private float mOutBlack = 0.0f;
-    private float mInWhite = 255.0f;
-    private float mOutWhite = 255.0f;
-    private float mSaturation = 1.0f;
-
-    Matrix3f satMatrix = new Matrix3f();
-    float mInWMinInB;
-    float mOutWMinOutB;
-    float mOverInWMinInB;
-
-    boolean mUseFull;
-    boolean mUseV4;
-
-    LevelsV4(boolean useFull, boolean useV4) {
-        mUseFull = useFull;
-        mUseV4 = useV4;
-    }
-
-
-    private void setLevels() {
-        mInWMinInB = mInWhite - mInBlack;
-        mOutWMinOutB = mOutWhite - mOutBlack;
-        mOverInWMinInB = 1.f / mInWMinInB;
-
-        mScriptR.set_inBlack(mInBlack);
-        mScriptR.set_outBlack(mOutBlack);
-        mScriptR.set_inWMinInB(mInWMinInB);
-        mScriptR.set_outWMinOutB(mOutWMinOutB);
-        mScriptR.set_overInWMinInB(mOverInWMinInB);
-        mScriptF.set_inBlack(mInBlack);
-        mScriptF.set_outBlack(mOutBlack);
-        mScriptF.set_inWMinInB(mInWMinInB);
-        mScriptF.set_outWMinOutB(mOutWMinOutB);
-        mScriptF.set_overInWMinInB(mOverInWMinInB);
-    }
-
-    private void setSaturation() {
-        float rWeight = 0.299f;
-        float gWeight = 0.587f;
-        float bWeight = 0.114f;
-        float oneMinusS = 1.0f - mSaturation;
-
-        satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
-        satMatrix.set(0, 1, oneMinusS * rWeight);
-        satMatrix.set(0, 2, oneMinusS * rWeight);
-        satMatrix.set(1, 0, oneMinusS * gWeight);
-        satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
-        satMatrix.set(1, 2, oneMinusS * gWeight);
-        satMatrix.set(2, 0, oneMinusS * bWeight);
-        satMatrix.set(2, 1, oneMinusS * bWeight);
-        satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
-        mScriptR.set_colorMat(satMatrix);
-        mScriptF.set_colorMat(satMatrix);
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        b.setProgress(50);
-        t.setText("Saturation");
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(0);
-        t.setText("In Black");
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(0);
-        t.setText("Out Black");
-        return true;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(128);
-        t.setText("Out White");
-        return true;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(128);
-        t.setText("Out White");
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        mSaturation = (float)progress / 50.0f;
-        setSaturation();
-    }
-    public void onBar2Changed(int progress) {
-        mInBlack = (float)progress;
-        setLevels();
-    }
-    public void onBar3Changed(int progress) {
-        mOutBlack = (float)progress;
-        setLevels();
-    }
-    public void onBar4Changed(int progress) {
-        mInWhite = (float)progress + 127.0f;
-        setLevels();
-    }
-    public void onBar5Changed(int progress) {
-        mOutWhite = (float)progress + 127.0f;
-        setLevels();
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mScriptR = new ScriptC_levels_relaxed(mRS, res, R.raw.levels_relaxed);
-        mScriptF = new ScriptC_levels_full(mRS, res, R.raw.levels_full);
-        setSaturation();
-        setLevels();
-    }
-
-    public void runTest() {
-        if (mUseFull) {
-            if (mUseV4) {
-                mScriptF.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
-            } else {
-                mScriptF.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-            }
-        } else {
-            if (mUseV4) {
-                mScriptR.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
-            } else {
-                mScriptR.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-            }
-        }
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Mandelbrot.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Mandelbrot.java
deleted file mode 100644
index 20036e6..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Mandelbrot.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Mandelbrot extends TestBase {
-    private ScriptC_mandelbrot mScript;
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Iterations");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        int iters = progress * 3 + 50;
-        mScript.set_gMaxIteration(iters);
-    }
-
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Lower Bound: X");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar2Changed(int progress) {
-        float scaleFactor = mScript.get_scaleFactor();
-        // allow viewport to be moved by 2x scale factor
-        float lowerBoundX = -2.f + ((progress / scaleFactor) / 50.f);
-        mScript.set_lowerBoundX(lowerBoundX);
-    }
-
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Lower Bound: Y");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar3Changed(int progress) {
-        float scaleFactor = mScript.get_scaleFactor();
-        // allow viewport to be moved by 2x scale factor
-        float lowerBoundY = -2.f + ((progress / scaleFactor) / 50.f);
-        mScript.set_lowerBoundY(lowerBoundY);
-    }
-
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        t.setText("Scale Factor");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar4Changed(int progress) {
-        float scaleFactor = 4.f - (3.96f * (progress / 100.f));
-        mScript.set_scaleFactor(scaleFactor);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mOutPixelsAllocation.getType().getX();
-        int height = mOutPixelsAllocation.getType().getY();
-
-        mScript = new ScriptC_mandelbrot(mRS, res, R.raw.mandelbrot);
-        mScript.set_gDimX(width);
-        mScript.set_gDimY(height);
-        mScript.set_gMaxIteration(50);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mOutPixelsAllocation);
-        mRS.finish();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Shadows.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Shadows.java
deleted file mode 100644
index 98ab15f..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Shadows.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-
-public class Shadows extends TestBase {
-    private ScriptC_shadows mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_shadows(mRS);
-    }
-
-    public void runTest() {
-        mScript.invoke_prepareShadows(50.f);
-        mScript.forEach_shadowsKernel(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
deleted file mode 100644
index a353d9c..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.renderscript.ScriptC;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Script;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.view.View;
-import android.util.Log;
-import java.lang.Math;
-import android.widget.Spinner;
-
-public class TestBase  {
-    protected final String TAG = "Img";
-
-    protected RenderScript mRS;
-    protected Allocation mInPixelsAllocation;
-    protected Allocation mInPixelsAllocation2;
-    protected Allocation mOutPixelsAllocation;
-    protected ImageProcessingActivity act;
-
-    private class MessageProcessor extends RenderScript.RSMessageHandler {
-        ImageProcessingActivity mAct;
-
-        MessageProcessor(ImageProcessingActivity act) {
-            mAct = act;
-        }
-
-        public void run() {
-            mAct.updateDisplay();
-        }
-    }
-
-    // Override to use UI elements
-    public void onBar1Changed(int progress) {
-    }
-    public void onBar2Changed(int progress) {
-    }
-    public void onBar3Changed(int progress) {
-    }
-    public void onBar4Changed(int progress) {
-    }
-    public void onBar5Changed(int progress) {
-    }
-
-    // Override to use UI elements
-    // Unused bars will be hidden.
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-
-    public boolean onSpinner1Setup(Spinner s) {
-        s.setVisibility(View.INVISIBLE);
-        return false;
-    }
-
-    public final void createBaseTest(ImageProcessingActivity ipact, Bitmap b, Bitmap b2, Bitmap outb) {
-        act = ipact;
-        mRS = ipact.mRS;
-        mRS.setMessageHandler(new MessageProcessor(act));
-
-        mInPixelsAllocation = ipact.mInPixelsAllocation;
-        mInPixelsAllocation2 = ipact.mInPixelsAllocation2;
-        mOutPixelsAllocation = ipact.mOutPixelsAllocation;
-
-        createTest(act.getResources());
-    }
-
-    // Must override
-    public void createTest(android.content.res.Resources res) {
-    }
-
-    // Must override
-    public void runTest() {
-    }
-
-    final public void runTestSendMessage() {
-        runTest();
-        mRS.sendMessage(0, null);
-    }
-
-    public void finish() {
-        mRS.finish();
-    }
-
-    public void destroy() {
-        mRS.setMessageHandler(null);
-    }
-
-    public void updateBitmap(Bitmap b) {
-        mOutPixelsAllocation.copyTo(b);
-    }
-
-    // Override to configure specific benchmark config.
-    public void setupBenchmark() {
-    }
-
-    // Override to reset after benchmark.
-    public void exitBenchmark() {
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/UsageIO.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/UsageIO.java
deleted file mode 100644
index 3f86311..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/UsageIO.java
+++ /dev/null
@@ -1,66 +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 com.android.rs.image;
-
-import java.lang.Math;
-
-import android.view.Surface;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.ScriptIntrinsicConvolve3x3;
-import android.renderscript.ScriptIntrinsicColorMatrix;
-import android.renderscript.Type;
-import android.renderscript.Matrix4f;
-import android.renderscript.ScriptGroup;
-import android.util.Log;
-
-public class UsageIO extends TestBase {
-    private ScriptIntrinsicColorMatrix mMatrix;
-
-    private Allocation mScratchPixelsAllocation1;
-    private Allocation mScratchPixelsAllocation2;
-
-    public UsageIO() {
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
-
-        Matrix4f m = new Matrix4f();
-        m.set(1, 0, 0.2f);
-        m.set(1, 1, 0.9f);
-        m.set(1, 2, 0.2f);
-        mMatrix.setColorMatrix(m);
-
-        Type connect = mInPixelsAllocation.getType();
-
-        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect, Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT);
-        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, connect, Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
-
-        Surface s = mScratchPixelsAllocation2.getSurface();
-        mScratchPixelsAllocation1.setSurface(s);
-    }
-
-    public void runTest() {
-        mScratchPixelsAllocation1.copyFrom(mInPixelsAllocation);
-        mScratchPixelsAllocation1.ioSend();
-        mScratchPixelsAllocation2.ioReceive();
-        mMatrix.forEach(mScratchPixelsAllocation2, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vibrance.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vibrance.java
deleted file mode 100644
index 0bc1ff7..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vibrance.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-
-public class Vibrance extends TestBase {
-    private ScriptC_vibrance mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_vibrance(mRS);
-    }
-
-    public void runTest() {
-        mScript.set_vibrance(50.f);
-        mScript.invoke_prepareVibrance();
-        mScript.forEach_vibranceKernel(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vignette.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vignette.java
deleted file mode 100644
index 18d1103..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Vignette.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Sampler;
-import android.renderscript.Type;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Vignette extends TestBase {
-    private ScriptC_vignette_full mScript_full = null;
-    private ScriptC_vignette_relaxed mScript_relaxed = null;
-    private ScriptC_vignette_approx_full mScript_approx_full = null;
-    private ScriptC_vignette_approx_relaxed mScript_approx_relaxed = null;
-    private final boolean approx;
-    private final boolean relaxed;
-    private float center_x = 0.5f;
-    private float center_y = 0.5f;
-    private float scale = 0.5f;
-    private float shade = 0.5f;
-    private float slope = 20.0f;
-
-    public Vignette(boolean approx, boolean relaxed) {
-        this.approx = approx;
-        this.relaxed = relaxed;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Scale");
-        b.setMax(100);
-        b.setProgress(25);
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Shade");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Slope");
-        b.setMax(100);
-        b.setProgress(20);
-        return true;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        t.setText("Shift center X");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        t.setText("Shift center Y");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        scale = progress / 50.0f;
-        do_init();
-    }
-    public void onBar2Changed(int progress) {
-        shade = progress / 100.0f;
-        do_init();
-    }
-    public void onBar3Changed(int progress) {
-        slope = (float)progress;
-        do_init();
-    }
-    public void onBar4Changed(int progress) {
-        center_x = progress / 100.0f;
-        do_init();
-    }
-    public void onBar5Changed(int progress) {
-        center_y = progress / 100.0f;
-        do_init();
-    }
-
-    private void do_init() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.invoke_init_vignette(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale, shade, slope);
-            else
-                mScript_approx_full.invoke_init_vignette(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale, shade, slope);
-        } else if (relaxed)
-            mScript_relaxed.invoke_init_vignette(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale, shade, slope);
-        else
-            mScript_full.invoke_init_vignette(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale, shade, slope);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed = new ScriptC_vignette_approx_relaxed(
-                        mRS, res, R.raw.vignette_approx_relaxed);
-            else
-                mScript_approx_full = new ScriptC_vignette_approx_full(
-                        mRS, res, R.raw.vignette_approx_full);
-        } else if (relaxed)
-            mScript_relaxed = new ScriptC_vignette_relaxed(mRS, res,
-                    R.raw.vignette_relaxed);
-        else
-            mScript_full = new ScriptC_vignette_full(mRS, res,
-                    R.raw.vignette_full);
-        do_init();
-    }
-
-    public void runTest() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.forEach_root(mInPixelsAllocation,
-                        mOutPixelsAllocation);
-            else
-                mScript_approx_full.forEach_root(mInPixelsAllocation,
-                        mOutPixelsAllocation);
-        } else if (relaxed)
-            mScript_relaxed.forEach_root(mInPixelsAllocation,
-                    mOutPixelsAllocation);
-        else
-            mScript_full.forEach_root(mInPixelsAllocation,
-                    mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/WhiteBalance.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/WhiteBalance.java
deleted file mode 100644
index a836067..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/WhiteBalance.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-
-public class WhiteBalance extends TestBase {
-    private ScriptC_wbalance mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_wbalance(mRS);
-    }
-
-    public void runTest() {
-        mScript.set_histogramSource(mInPixelsAllocation);
-        mScript.set_histogramWidth(mInPixelsAllocation.getType().getX());
-        mScript.set_histogramHeight(mInPixelsAllocation.getType().getY());
-        mScript.invoke_prepareWhiteBalance();
-        mScript.forEach_whiteBalanceKernel(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs
deleted file mode 100644
index 87b56f7..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2011 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-uchar alpha = 0x0;
-
-void setImageAlpha(uchar4 *v_out, uint32_t x, uint32_t y) {
-  v_out->rgba = convert_uchar4((convert_uint4(v_out->rgba) * alpha) >> (uint4)8);
-  v_out->a = alpha;
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/bwfilter.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/bwfilter.rs
deleted file mode 100644
index 03e5a79..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/bwfilter.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-//#pragma rs_fp_relaxed
-
-static float sr = 0.f;
-static float sg = 0.f;
-static float sb = 0.f;
-
-void prepareBwFilter(uint32_t rw, uint32_t gw, uint32_t bw) {
-
-    sr = rw;
-    sg = gw;
-    sb = bw;
-
-    float imageMin = min(sg,sb);
-    imageMin = fmin(sr,imageMin);
-    float imageMax = max(sg,sb);
-    imageMax = fmax(sr,imageMax);
-    float avg = (imageMin + imageMax)/2;
-    sb /= avg;
-    sg /= avg;
-    sr /= avg;
-
-}
-
-void bwFilterKernel(const uchar4 *in, uchar4 *out) {
-    float r = in->r * sr;
-    float g = in->g * sg;
-    float b = in->b * sb;
-    float localMin, localMax, avg;
-    localMin = fmin(g,b);
-    localMin = fmin(r,localMin);
-    localMax = fmax(g,b);
-    localMax = fmax(r,localMax);
-    avg = (localMin+localMax) * 0.5f;
-    out->r = out->g = out->b = rsClamp(avg, 0, 255);
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colorcube.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colorcube.rs
deleted file mode 100644
index fda0d1e..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colorcube.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-
-static rs_allocation gCube;
-static int4 gDims;
-static int4 gCoordMul;
-
-
-void setCube(rs_allocation c) {
-    gCube = c;
-    gDims.x = rsAllocationGetDimX(gCube);
-    gDims.y = rsAllocationGetDimY(gCube);
-    gDims.z = rsAllocationGetDimZ(gCube);
-    gDims.w = 0;
-
-    float4 m = (float4)(1.f / 255.f) * convert_float4(gDims - 1);
-    gCoordMul = convert_int4(m * (float4)0x10000);
-
-    rsDebug("dims", gDims);
-    rsDebug("gCoordMul", gCoordMul);
-}
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    //rsDebug("root", in);
-
-    int4 baseCoord = convert_int4(*in) * gCoordMul;
-    int4 coord1 = baseCoord >> (int4)16;
-    int4 coord2 = min(coord1 + 1, gDims - 1);
-
-    int4 weight2 = baseCoord & 0xffff;
-    int4 weight1 = (int4)0x10000 - weight2;
-
-    uint4 v000 = convert_uint4(rsGetElementAt_uchar4(gCube, coord1.x, coord1.y, coord1.z));
-    uint4 v100 = convert_uint4(rsGetElementAt_uchar4(gCube, coord2.x, coord1.y, coord1.z));
-    uint4 v010 = convert_uint4(rsGetElementAt_uchar4(gCube, coord1.x, coord2.y, coord1.z));
-    uint4 v110 = convert_uint4(rsGetElementAt_uchar4(gCube, coord2.x, coord2.y, coord1.z));
-    uint4 v001 = convert_uint4(rsGetElementAt_uchar4(gCube, coord1.x, coord1.y, coord2.z));
-    uint4 v101 = convert_uint4(rsGetElementAt_uchar4(gCube, coord2.x, coord1.y, coord2.z));
-    uint4 v011 = convert_uint4(rsGetElementAt_uchar4(gCube, coord1.x, coord2.y, coord2.z));
-    uint4 v111 = convert_uint4(rsGetElementAt_uchar4(gCube, coord2.x, coord2.y, coord2.z));
-
-    uint4 yz00 = ((v000 * weight1.x) + (v100 * weight2.x)) >> (int4)8;
-    uint4 yz10 = ((v010 * weight1.x) + (v110 * weight2.x)) >> (int4)8;
-    uint4 yz01 = ((v001 * weight1.x) + (v101 * weight2.x)) >> (int4)8;
-    uint4 yz11 = ((v011 * weight1.x) + (v111 * weight2.x)) >> (int4)8;
-
-    uint4 z0 = ((yz00 * weight1.y) + (yz10 * weight2.y)) >> (int4)16;
-    uint4 z1 = ((yz01 * weight1.y) + (yz11 * weight2.y)) >> (int4)16;
-
-    uint4 v = ((z0 * weight1.z) + (z1 * weight2.z)) >> (int4)16;
-    uint4 v2 = (v + 0x7f) >> (int4)8;
-
-    *out = convert_uchar4(v2);
-    out->a = 0xff;
-
-    #if 0
-    if (in->r != out->r) {
-        rsDebug("dr", in->r - out->r);
-        //rsDebug("in", convert_int4(*in));
-        //rsDebug("coord1", coord1);
-        //rsDebug("coord2", coord2);
-        //rsDebug("weight1", weight1);
-        //rsDebug("weight2", weight2);
-        //rsDebug("yz00", yz00);
-        //rsDebug("z0", z0);
-        //rsDebug("v", v);
-        //rsDebug("v2", v2);
-        //rsDebug("out", convert_int4(*out));
-    }
-    #endif
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.fs
deleted file mode 100644
index ba8711b..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.fs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-
-static rs_matrix4x4 Mat;
-
-void init() {
-    rsMatrixLoadIdentity(&Mat);
-}
-
-void setMatrix(rs_matrix4x4 m) {
-    Mat = m;
-}
-
-uchar4 __attribute__((kernel)) root(uchar4 in) {
-    float4 f = convert_float4(in);
-    f = rsMatrixMultiply(&Mat, f);
-    f = clamp(f, 0.f, 255.f);
-    return convert_uchar4(f);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/contrast.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/contrast.rs
deleted file mode 100644
index 5fd7be1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/contrast.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_full
-
-static float brightM = 0.f;
-static float brightC = 0.f;
-
-void setBright(float v) {
-    brightM = pow(2.f, v / 100.f);
-    brightC = 127.f - brightM * 127.f;
-}
-
-void contrast(const uchar4 *in, uchar4 *out)
-{
-#if 0
-    out->r = rsClamp((int)(brightM * in->r + brightC), 0, 255);
-    out->g = rsClamp((int)(brightM * in->g + brightC), 0, 255);
-    out->b = rsClamp((int)(brightM * in->b + brightC), 0, 255);
-#else
-    float3 v = convert_float3(in->rgb) * brightM + brightC;
-    out->rgb = convert_uchar3(clamp(v, 0.f, 255.f));
-#endif
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.fs
deleted file mode 100644
index 772503f..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.fs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-int32_t gWidth;
-int32_t gHeight;
-rs_allocation gIn;
-
-float gCoeffs[9];
-
-uchar4 __attribute__((kernel)) root(uint32_t x, uint32_t y) {
-    uint32_t x1 = min((int32_t)x+1, gWidth-1);
-    uint32_t x2 = max((int32_t)x-1, 0);
-    uint32_t y1 = min((int32_t)y+1, gHeight-1);
-    uint32_t y2 = max((int32_t)y-1, 0);
-
-    float4 p00 = convert_float4(rsGetElementAt_uchar4(gIn, x1, y1));
-    float4 p01 = convert_float4(rsGetElementAt_uchar4(gIn, x, y1));
-    float4 p02 = convert_float4(rsGetElementAt_uchar4(gIn, x2, y1));
-    float4 p10 = convert_float4(rsGetElementAt_uchar4(gIn, x1, y));
-    float4 p11 = convert_float4(rsGetElementAt_uchar4(gIn, x, y));
-    float4 p12 = convert_float4(rsGetElementAt_uchar4(gIn, x2, y));
-    float4 p20 = convert_float4(rsGetElementAt_uchar4(gIn, x1, y2));
-    float4 p21 = convert_float4(rsGetElementAt_uchar4(gIn, x, y2));
-    float4 p22 = convert_float4(rsGetElementAt_uchar4(gIn, x2, y2));
-    p00 *= gCoeffs[0];
-    p01 *= gCoeffs[1];
-    p02 *= gCoeffs[2];
-    p10 *= gCoeffs[3];
-    p11 *= gCoeffs[4];
-    p12 *= gCoeffs[5];
-    p20 *= gCoeffs[6];
-    p21 *= gCoeffs[7];
-    p22 *= gCoeffs[8];
-
-    p00 += p01;
-    p02 += p10;
-    p11 += p12;
-    p20 += p21;
-
-    p22 += p00;
-    p02 += p11;
-
-    p20 += p22;
-    p20 += p02;
-
-    p20 = clamp(p20, 0.f, 255.f);
-    return convert_uchar4(p20);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve5x5.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve5x5.fs
deleted file mode 100644
index a916bfb..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve5x5.fs
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-int32_t gWidth;
-int32_t gHeight;
-rs_allocation gIn;
-
-float gCoeffs[25];
-
-uchar4 __attribute__((kernel)) root(uint32_t x, uint32_t y) {
-    uint32_t x0 = max((int32_t)x-2, 0);
-    uint32_t x1 = max((int32_t)x-1, 0);
-    uint32_t x2 = x;
-    uint32_t x3 = min((int32_t)x+1, gWidth-1);
-    uint32_t x4 = min((int32_t)x+2, gWidth-1);
-
-    uint32_t y0 = max((int32_t)y-2, 0);
-    uint32_t y1 = max((int32_t)y-1, 0);
-    uint32_t y2 = y;
-    uint32_t y3 = min((int32_t)y+1, gHeight-1);
-    uint32_t y4 = min((int32_t)y+2, gHeight-1);
-
-    float4 p0 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y0)) * gCoeffs[0]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y0)) * gCoeffs[1]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y0)) * gCoeffs[2]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y0)) * gCoeffs[3]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y0)) * gCoeffs[4];
-
-    float4 p1 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y1)) * gCoeffs[5]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y1)) * gCoeffs[6]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y1)) * gCoeffs[7]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y1)) * gCoeffs[8]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y1)) * gCoeffs[9];
-
-    float4 p2 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y2)) * gCoeffs[10]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y2)) * gCoeffs[11]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y2)) * gCoeffs[12]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y2)) * gCoeffs[13]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y2)) * gCoeffs[14];
-
-    float4 p3 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y3)) * gCoeffs[15]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y3)) * gCoeffs[16]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y3)) * gCoeffs[17]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y3)) * gCoeffs[18]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y3)) * gCoeffs[19];
-
-    float4 p4 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y4)) * gCoeffs[20]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y4)) * gCoeffs[21]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y4)) * gCoeffs[22]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y4)) * gCoeffs[23]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y4)) * gCoeffs[24];
-
-    p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
-    return convert_uchar4(p0);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/copy.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/copy.fs
deleted file mode 100644
index 5f03483..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/copy.fs
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-uchar4 __attribute__((kernel)) root(uchar4 v_in) {
-    return v_in;
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/exposure.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/exposure.rs
deleted file mode 100644
index adfae4a..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/exposure.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_full
-
-static float bright = 0.f;
-
-void setBright(float v) {
-    bright = 255.f / (255.f - v);
-}
-
-void exposure(const uchar4 *in, uchar4 *out)
-{
-    out->r = rsClamp((int)(bright * in->r), 0, 255);
-    out->g = rsClamp((int)(bright * in->g), 0, 255);
-    out->b = rsClamp((int)(bright * in->b), 0, 255);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh
deleted file mode 100644
index 2eacb7d..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-rs_allocation in_alloc;
-rs_sampler sampler;
-
-static float2 center, neg_center, inv_dimensions, axis_scale;
-static float alpha, radius2, factor;
-
-void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) {
-    center.x = center_x;
-    center.y = center_y;
-    neg_center = -center;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-    alpha = k * 2.0f + 0.75f;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-    
-    const float bound2 = 0.25f * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y);
-    const float bound = sqrt(bound2);
-    const float radius = 1.15f * bound;
-    radius2 = radius*radius;
-    const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2));
-    factor = bound / max_radian;
-}
-
-uchar4 __attribute__((kernel)) root(uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float2 scaledCoord = axis_scale * coord;
-    const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
-    const float inv_dist = rsqrt(dist2);
-    const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist2)) * inv_dist);
-    const float scalar = radian * factor * inv_dist;
-    const float2 new_coord = mad(coord, scalar, center);
-    const float4 fout = rsSample(in_alloc, sampler, new_coord);
-    return rsPackColorTo8888(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
deleted file mode 100644
index fcf0a3d..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-rs_allocation in_alloc;
-rs_sampler sampler;
-
-static float2 center, neg_center, inv_dimensions, axis_scale;
-static float alpha, radius2, factor;
-
-void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) {
-    center.x = center_x;
-    center.y = center_y;
-    neg_center = -center;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-    alpha = k * 2.0f + 0.75f;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float bound2 = 0.25f * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y);
-    const float bound = sqrt(bound2);
-    const float radius = 1.15f * bound;
-    radius2 = radius*radius;
-    const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2));
-    factor = bound / max_radian;
-}
-
-uchar4 __attribute__((kernel)) root(uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float2 scaledCoord = axis_scale * coord;
-    const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
-    const float inv_dist = half_rsqrt(dist2);
-    const float radian = M_PI_2 - atan((alpha * half_sqrt(radius2 - dist2)) * inv_dist);
-    const float scalar = radian * factor * inv_dist;
-    const float2 new_coord = mad(coord, scalar, center);
-    const float4 fout = rsSample(in_alloc, sampler, new_coord);
-    return rsPackColorTo8888(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_full.rs
deleted file mode 100644
index 1ea37db..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-#include "fisheye_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_relaxed.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_relaxed.fs
deleted file mode 100644
index 3e76368..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_relaxed.fs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-#include "fisheye_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_full.rs
deleted file mode 100644
index 20f27e2..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-#include "fisheye.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_relaxed.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_relaxed.fs
deleted file mode 100644
index dc3ffcb..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_relaxed.fs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-#include "fisheye.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.fs
deleted file mode 100644
index 4ae095d..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.fs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-uchar __attribute__((kernel)) genRand() {
-    return (uchar)rsRand(0xff);
-}
-
-/*
- * Convolution matrix of distance 2 with fixed point of 'kShiftBits' bits
- * shifted. Thus the sum of this matrix should be 'kShiftValue'. Entries of
- * small values are not calculated to gain efficiency.
- * The order ot pixels represented in this matrix is:
- *  1  2  3
- *  4  0  5
- *  6  7  8
- *  and the matrix should be: {230, 56, 114, 56, 114, 114, 56, 114, 56}.
- *  However, since most of the valus are identical, we only use the first three
- *  entries and the entries corresponding to the pixels is:
- *  1  2  1
- *  2  0  2
- *  1  2  1
- */
-
-int32_t gWMask;
-int32_t gHMask;
-
-rs_allocation gBlendSource;
-uchar __attribute__((kernel)) blend9(uint32_t x, uint32_t y) {
-    uint32_t x1 = (x-1) & gWMask;
-    uint32_t x2 = (x+1) & gWMask;
-    uint32_t y1 = (y-1) & gHMask;
-    uint32_t y2 = (y+1) & gHMask;
-
-    uint p00 = 56 *  rsGetElementAt_uchar(gBlendSource, x1, y1);
-    uint p01 = 114 * rsGetElementAt_uchar(gBlendSource, x, y1);
-    uint p02 = 56 *  rsGetElementAt_uchar(gBlendSource, x2, y1);
-    uint p10 = 114 * rsGetElementAt_uchar(gBlendSource, x1, y);
-    uint p11 = 230 * rsGetElementAt_uchar(gBlendSource, x, y);
-    uint p12 = 114 * rsGetElementAt_uchar(gBlendSource, x2, y);
-    uint p20 = 56 *  rsGetElementAt_uchar(gBlendSource, x1, y2);
-    uint p21 = 114 * rsGetElementAt_uchar(gBlendSource, x, y2);
-    uint p22 = 56 *  rsGetElementAt_uchar(gBlendSource, x2, y2);
-
-    p00 += p01;
-    p02 += p10;
-    p11 += p12;
-    p20 += p21;
-
-    p22 += p00;
-    p02 += p11;
-
-    p20 += p22;
-    p20 += p02;
-
-    p20 = min(p20 >> 10, (uint)255);
-    return (uchar)p20;
-}
-
-float gNoiseStrength;
-
-rs_allocation gNoise;
-uchar4 __attribute__((kernel)) root(uchar4 in, uint32_t x, uint32_t y) {
-    float4 ip = convert_float4(in);
-    float pnoise = (float) rsGetElementAt_uchar(gNoise, x & gWMask, y & gHMask);
-
-    float energy_level = ip.r + ip.g + ip.b;
-    float energy_mask = (28.f - sqrt(energy_level)) * 0.03571f;
-    pnoise = (pnoise - 128.f) * energy_mask;
-
-    ip += pnoise * gNoiseStrength;
-    ip = clamp(ip, 0.f, 255.f);
-
-    uchar4 p = convert_uchar4(ip);
-    p.a = 0xff;
-    return p;
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/greyscale.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/greyscale.fs
deleted file mode 100644
index d419459..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/greyscale.fs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-
-uchar4 __attribute__((kernel)) root(uchar4 v_in) {
-    float4 f4 = rsUnpackColor8888(v_in);
-
-    float3 mono = dot(f4.rgb, gMonoMult);
-    return rsPackColorTo8888(mono);
-}
-
-uchar __attribute__((kernel)) toU8(uchar4 v_in) {
-    float4 f4 = convert_float4(v_in);
-    return (uchar)dot(f4.rgb, gMonoMult);
-}
-
-uchar4 __attribute__((kernel)) toU8_4(uchar v_in) {
-    return (uchar4)v_in;
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels.rsh
deleted file mode 100644
index e289906..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels.rsh
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-float inBlack;
-float outBlack;
-float inWMinInB;
-float outWMinOutB;
-float overInWMinInB;
-rs_matrix3x3 colorMat;
-
-uchar4 __attribute__((kernel)) root(uchar4 in, uint32_t x, uint32_t y) {
-    uchar4 out;
-    float3 pixel = convert_float4(in).rgb;
-    pixel = rsMatrixMultiply(&colorMat, pixel);
-    pixel = clamp(pixel, 0.f, 255.f);
-    pixel = (pixel - inBlack) * overInWMinInB;
-    pixel = pixel * outWMinOutB + outBlack;
-    pixel = clamp(pixel, 0.f, 255.f);
-    out.xyz = convert_uchar3(pixel);
-    out.w = 0xff;
-    return out;
-}
-
-uchar4 __attribute__((kernel)) root4(uchar4 in, uint32_t x, uint32_t y) {
-    float4 pixel = convert_float4(in);
-    pixel.rgb = rsMatrixMultiply(&colorMat, pixel.rgb);
-    pixel = clamp(pixel, 0.f, 255.f);
-    pixel = (pixel - inBlack) * overInWMinInB;
-    pixel = pixel * outWMinOutB + outBlack;
-    pixel = clamp(pixel, 0.f, 255.f);
-    return convert_uchar4(pixel);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_full.rs
deleted file mode 100644
index da6a291..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-#include "levels.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_relaxed.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_relaxed.fs
deleted file mode 100644
index b115445..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/levels_relaxed.fs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-#include "levels.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs
deleted file mode 100644
index ac2061b..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/mandelbrot.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2011 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-uint32_t gMaxIteration = 500;
-uint32_t gDimX = 1024;
-uint32_t gDimY = 1024;
-
-float lowerBoundX = -2.f;
-float lowerBoundY = -2.f;
-float scaleFactor = 4.f;
-
-uchar4 __attribute__((kernel)) root(uint32_t x, uint32_t y) {
-  float2 p;
-  p.x = lowerBoundX + ((float)x / gDimX) * scaleFactor;
-  p.y = lowerBoundY + ((float)y / gDimY) * scaleFactor;
-
-  float2 t = 0;
-  float2 t2 = t * t;
-  int iter = 0;
-  while((t2.x + t2.y < 4.f) && (iter < gMaxIteration)) {
-    float xtemp = t2.x - t2.y + p.x;
-    t.y = 2 * t.x * t.y + p.y;
-    t.x = xtemp;
-    iter++;
-    t2 = t * t;
-  }
-
-  if(iter >= gMaxIteration) {
-    // write a non-transparent black pixel
-    return (uchar4){0, 0, 0, 0xff};
-  } else {
-    float mi3 = gMaxIteration / 3.f;
-    if (iter <= (gMaxIteration / 3))
-      return (uchar4){0xff * (iter / mi3), 0, 0, 0xff};
-    else if (iter <= (((gMaxIteration / 3) * 2)))
-      return (uchar4){0xff - (0xff * ((iter - mi3) / mi3)),
-                      (0xff * ((iter - mi3) / mi3)), 0, 0xff};
-    else
-      return (uchar4){0, 0xff - (0xff * ((iter - (mi3 * 2)) / mi3)),
-                      (0xff * ((iter - (mi3 * 2)) / mi3)), 0xff};
-  }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/shadows.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/shadows.rs
deleted file mode 100644
index 7ee3405..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/shadows.rs
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-//#pragma rs_fp_relaxed
-
-static double shadowFilterMap[] = {
-    -0.00591,  0.0001,
-     1.16488,  0.01668,
-    -0.18027, -0.06791,
-    -0.12625,  0.09001,
-     0.15065, -0.03897
-};
-
-static double poly[] = {
-    0., 0.,
-    0., 0.,
-    0.
-};
-
-static const int ABITS = 4;
-static const int HSCALE = 256;
-static const int k1=255 << ABITS;
-static const int k2=HSCALE << ABITS;
-
-static double fastevalPoly(double *poly,int n, double x){
-
-    double f =x;
-    double sum = poly[0]+poly[1]*f;
-    int i;
-    for (i = 2; i < n; i++) {
-        f*=x;
-        sum += poly[i]*f;
-    }
-    return sum;
-}
-
-static ushort3 rgb2hsv( uchar4 rgb)
-{
-    int iMin,iMax,chroma;
-
-    int ri = rgb.r;
-    int gi = rgb.g;
-    int bi = rgb.b;
-    short rv,rs,rh;
-
-    if (ri > gi) {
-        iMax = max (ri, bi);
-        iMin = min (gi, bi);
-    } else {
-        iMax = max (gi, bi);
-        iMin = min (ri, bi);
-    }
-
-    chroma = iMax - iMin;
-    // set value
-    rv = (short)( iMax << ABITS);
-
-    // set saturation
-    if (rv == 0)
-        rs = 0;
-    else
-        rs = (short)((k1*chroma)/iMax);
-
-    // set hue
-    if (rs == 0)
-        rh = 0;
-    else {
-        if ( ri == iMax ) {
-            rh  = (short)( (k2*(6*chroma+gi - bi))/(6*chroma));
-            if (rh >= k2) rh -= k2;
-        } else if (gi  == iMax)
-            rh  = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma));
-        else // (bi == iMax )
-                    rh  = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma));
-    }
-
-    ushort3 out;
-    out.x = rv;
-    out.y = rs;
-    out.z = rh;
-    return out;
-}
-
-static uchar4 hsv2rgb(ushort3 hsv)
-{
-    int ABITS = 4;
-    int HSCALE = 256;
-    int m;
-    int H,X,ih,is,iv;
-    int k1=255<<ABITS;
-    int k2=HSCALE<<ABITS;
-    int k3=1<<(ABITS-1);
-    int rr=0;
-    int rg=0;
-    int rb=0;
-    short cv = hsv.x;
-    short cs = hsv.y;
-    short ch = hsv.z;
-
-    // set chroma and min component value m
-    //chroma = ( cv * cs )/k1;
-    //m = cv - chroma;
-    m = ((int)cv*(k1 - (int)cs ))/k1;
-
-    // chroma  == 0 <-> cs == 0 --> m=cv
-    if (cs == 0) {
-        rb = ( rg = ( rr =( cv >> ABITS) ));
-    } else {
-        ih=(int)ch;
-        is=(int)cs;
-        iv=(int)cv;
-
-        H = (6*ih)/k2;
-        X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ;
-
-        // removing additional bits --> unit8
-        X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS;
-        m=m >> ABITS;
-
-        // ( chroma + m ) --> cv ;
-        cv=(short) (cv >> ABITS);
-        switch (H) {
-        case 0:
-            rr = cv;
-            rg = X;
-            rb = m;
-            break;
-        case 1:
-            rr = X;
-            rg = cv;
-            rb = m;
-            break;
-        case 2:
-            rr = m;
-            rg = cv;
-            rb = X;
-            break;
-        case 3:
-            rr = m;
-            rg = X;
-            rb = cv;
-            break;
-        case 4:
-            rr = X;
-            rg = m;
-            rb = cv;
-            break;
-        case 5:
-            rr = cv;
-            rg = m ;
-            rb = X;
-            break;
-        }
-    }
-
-    uchar4 rgb;
-
-    rgb.r =  rr;
-    rgb.g =  rg;
-    rgb.b =  rb;
-
-    return rgb;
-}
-
-void prepareShadows(float scale) {
-    double s = (scale>=0)?scale:scale/5;
-    for (int i = 0; i < 5; i++) {
-        poly[i] = fastevalPoly(shadowFilterMap+i*2,2 , s);
-    }
-}
-
-void shadowsKernel(const uchar4 *in, uchar4 *out) {
-    ushort3 hsv = rgb2hsv(*in);
-    double v = (fastevalPoly(poly,5,hsv.x/4080.)*4080);
-    if (v>4080) v = 4080;
-    hsv.x = (unsigned short) ((v>0)?v:0);
-    *out = hsv2rgb(hsv);
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.fs
deleted file mode 100644
index 86e155a..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.fs
+++ /dev/null
@@ -1,104 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-
-int height;
-int width;
-static int radius;
-
-rs_allocation InPixel;
-rs_allocation ScratchPixel1;
-rs_allocation ScratchPixel2;
-
-const int MAX_RADIUS = 25;
-
-// Store our coefficients here
-static float gaussian[MAX_RADIUS * 2 + 1];
-
-void setRadius(int rad) {
-    radius = rad;
-    // Compute gaussian weights for the blur
-    // e is the euler's number
-    float e = 2.718281828459045f;
-    float pi = 3.1415926535897932f;
-    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
-    // x is of the form [-radius .. 0 .. radius]
-    // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.4  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.4f * (float)radius + 0.6f;
-
-    // Now compute the coefficints
-    // We will store some redundant values to save some math during
-    // the blur calculations
-    // precompute some values
-    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
-    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
-
-    float normalizeFactor = 0.0f;
-    float floatR = 0.0f;
-    for (int r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
-        normalizeFactor += gaussian[r + radius];
-    }
-
-    //Now we need to normalize the weights because all our coefficients need to add up to one
-    normalizeFactor = 1.0f / normalizeFactor;
-    for (int r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] *= normalizeFactor;
-    }
-}
-
-float4 __attribute__((kernel)) copyIn(uchar4 in) {
-    return convert_float4(in);
-}
-
-uchar4 __attribute__((kernel)) vert(uint32_t x, uint32_t y) {
-    float3 blurredPixel = 0;
-    int gi = 0;
-    uchar4 out;
-    if ((y > radius) && (y < (height - radius))) {
-        for (int r = -radius; r <= radius; r ++) {
-            float4 i = rsGetElementAt_float4(ScratchPixel2, x, y + r);
-            blurredPixel += i.xyz * gaussian[gi++];
-        }
-    } else {
-        for (int r = -radius; r <= radius; r ++) {
-            int validH = rsClamp((int)y + r, (int)0, (int)(height - 1));
-            float4 i = rsGetElementAt_float4(ScratchPixel2, x, validH);
-            blurredPixel += i.xyz * gaussian[gi++];
-        }
-    }
-
-    out.xyz = convert_uchar3(clamp(blurredPixel, 0.f, 255.f));
-    out.w = 0xff;
-    return out;
-}
-
-float4 __attribute__((kernel)) horz(uint32_t x, uint32_t y) {
-    float4 blurredPixel = 0;
-    int gi = 0;
-    if ((x > radius) && (x < (width - radius))) {
-        for (int r = -radius; r <= radius; r ++) {
-            float4 i = rsGetElementAt_float4(ScratchPixel1, x + r, y);
-            blurredPixel += i * gaussian[gi++];
-        }
-    } else {
-        for (int r = -radius; r <= radius; r ++) {
-            // Stepping left and right away from the pixel
-            int validX = rsClamp((int)x + r, (int)0, (int)(width - 1));
-            float4 i = rsGetElementAt_float4(ScratchPixel1, validX, y);
-            blurredPixel += i * gaussian[gi++];
-        }
-    }
-
-    return blurredPixel;
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vibrance.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vibrance.rs
deleted file mode 100644
index fae94a1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vibrance.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-float vibrance = 0.f;
-
-static const float Rf = 0.2999f;
-static const float Gf = 0.587f;
-static const float Bf = 0.114f;
-
-static float S  = 0.f;
-static float MS = 0.f;
-static float Rt = 0.f;
-static float Gt = 0.f;
-static float Bt = 0.f;
-static float Vib = 0.f;
-
-void vibranceKernel(const uchar4 *in, uchar4 *out) {
-
-    float R, G, B;
-
-    int r = in->r;
-    int g = in->g;
-    int b = in->b;
-    float red = (r-max(g, b))/256.f;
-    float sx = (float)(Vib/(1+native_exp(-red*3)));
-    S = sx+1;
-    MS = 1.0f - S;
-    Rt = Rf * MS;
-    Gt = Gf * MS;
-    Bt = Bf * MS;
-    int t = (r + g) / 2;
-    R = r;
-    G = g;
-    B = b;
-
-    float Rc = R * (Rt + S) + G * Gt + B * Bt;
-    float Gc = R * Rt + G * (Gt + S) + B * Bt;
-    float Bc = R * Rt + G * Gt + B * (Bt + S);
-
-    out->r = rsClamp(Rc, 0, 255);
-    out->g = rsClamp(Gc, 0, 255);
-    out->b = rsClamp(Bc, 0, 255);
-
-}
-
-void prepareVibrance() {
-
-    Vib = vibrance/100.f;
-    S  = Vib + 1;
-    MS = 1.0f - S;
-    Rt = Rf * MS;
-    Gt = Gf * MS;
-    Bt = Bf * MS;
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette.rsh
deleted file mode 100644
index 04ca1f1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette.rsh
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-static float2 neg_center, axis_scale, inv_dimensions;
-static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade;
-
-void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y,
-        float desired_scale, float desired_shade, float desired_slope) {
-
-    neg_center.x = -center_x;
-    neg_center.y = -center_y;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float max_dist = 0.5f * length(axis_scale);
-    sloped_inv_max_dist = desired_slope * 1.f/max_dist;
-
-    // Range needs to be between 1.3 to 0.6. When scale is zero then range is
-    // 1.3 which means no vignette at all because the luminousity difference is
-    // less than 1/256.  Expect input scale to be between 0.0 and 1.0.
-    const float neg_range = 0.7f*sqrt(desired_scale) - 1.3f;
-    sloped_neg_range = exp(neg_range * desired_slope);
-
-    shade = desired_shade;
-    opp_shade = 1.f - desired_shade;
-}
-
-uchar4 __attribute__((kernel)) root(uchar4 in, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float4 fin = convert_float4(in);
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float sloped_dist_ratio = length(axis_scale * coord)  * sloped_inv_max_dist;
-    const float lumen = opp_shade + shade / ( 1.0f + sloped_neg_range * exp(sloped_dist_ratio) );
-    float4 fout;
-    fout.rgb = fin.rgb * lumen;
-    fout.w = fin.w;
-    return convert_uchar4(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh
deleted file mode 100644
index 5668621..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx.rsh
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-static float2 neg_center, axis_scale, inv_dimensions;
-static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade;
-
-void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y,
-        float desired_scale, float desired_shade, float desired_slope) {
-
-    neg_center.x = -center_x;
-    neg_center.y = -center_y;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float max_dist = 0.5f * length(axis_scale);
-    sloped_inv_max_dist = desired_slope * 1.f/max_dist;
-
-    // Range needs to be between 1.3 to 0.6. When scale is zero then range is
-    // 1.3 which means no vignette at all because the luminousity difference is
-    // less than 1/256.  Expect input scale to be between 0.0 and 1.0.
-    const float neg_range = 0.7f*sqrt(desired_scale) - 1.3f;
-    sloped_neg_range = exp(neg_range * desired_slope);
-
-    shade = desired_shade;
-    opp_shade = 1.f - desired_shade;
-}
-
-uchar4 __attribute__((kernel)) root(uchar4 in, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float4 fin = convert_float4(in);
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float sloped_dist_ratio = fast_length(axis_scale * coord)  * sloped_inv_max_dist;
-    const float lumen = opp_shade + shade * half_recip(1.f + sloped_neg_range * native_exp(sloped_dist_ratio));
-    float4 fout;
-    fout.rgb = fin.rgb * lumen;
-    fout.w = fin.w;
-    return convert_uchar4(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx_full.rs
deleted file mode 100644
index c83c6e1..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-#include "vignette_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx_relaxed.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx_relaxed.fs
deleted file mode 100644
index 9120612..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_approx_relaxed.fs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-#include "vignette_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_full.rs
deleted file mode 100644
index 64942d9..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-
-#include "vignette.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_relaxed.fs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_relaxed.fs
deleted file mode 100644
index 8e47ea9..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/vignette_relaxed.fs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-#pragma rs_fp_relaxed
-
-#include "vignette.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/wbalance.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/wbalance.rs
deleted file mode 100644
index 8c825f2..0000000
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/wbalance.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image)
-//#pragma rs_fp_relaxed
-
-static int histR[256] = {0}, histG[256] = {0}, histB[256] = {0};
-
-rs_allocation histogramSource;
-uint32_t histogramHeight;
-uint32_t histogramWidth;
-
-static float scaleR;
-static float scaleG;
-static float scaleB;
-
-static uchar4 estimateWhite() {
-
-    for (int i = 0; i < 256; i++) {
-        histR[i] = 0; histG[i] = 0; histB[i] = 0;
-    }
-
-    for (uint32_t i = 0; i < histogramHeight; i++) {
-        for (uint32_t j = 0; j < histogramWidth; j++) {
-            uchar4 in = rsGetElementAt_uchar4(histogramSource, j, i);
-            histR[in.r]++;
-            histG[in.g]++;
-            histB[in.b]++;
-        }
-    }
-
-    int min_r = -1, min_g = -1, min_b = -1;
-    int max_r =  0, max_g =  0, max_b =  0;
-    int sum_r =  0, sum_g =  0, sum_b =  0;
-
-    for (int i = 1; i < 255; i++) {
-        int r = histR[i];
-        int g = histG[i];
-        int b = histB[i];
-        sum_r += r;
-        sum_g += g;
-        sum_b += b;
-
-        if (r>0){
-            if (min_r < 0) min_r = i;
-            max_r = i;
-        }
-        if (g>0){
-            if (min_g < 0) min_g = i;
-            max_g = i;
-        }
-        if (b>0){
-            if (min_b < 0) min_b = i;
-            max_b = i;
-        }
-    }
-
-    int sum15r = 0, sum15g = 0, sum15b = 0;
-    int count15r = 0, count15g = 0, count15b = 0;
-    int tmp_r = 0, tmp_g = 0, tmp_b = 0;
-
-    for (int i = 254; i >0; i--) {
-        int r = histR[i];
-        int g = histG[i];
-        int b = histB[i];
-        tmp_r += r;
-        tmp_g += g;
-        tmp_b += b;
-
-        if ((tmp_r > sum_r/20) && (tmp_r < sum_r/5)) {
-            sum15r += r*i;
-            count15r += r;
-        }
-        if ((tmp_g > sum_g/20) && (tmp_g < sum_g/5)) {
-            sum15g += g*i;
-            count15g += g;
-        }
-        if ((tmp_b > sum_b/20) && (tmp_b < sum_b/5)) {
-            sum15b += b*i;
-            count15b += b;
-        }
-
-    }
-
-    uchar4 out;
-
-    if ((count15r>0) && (count15g>0) && (count15b>0) ){
-        out.r = sum15r/count15r;
-        out.g = sum15g/count15g;
-        out.b = sum15b/count15b;
-    }else {
-        out.r = out.g = out.b = 255;
-    }
-
-    return out;
-
-}
-
-void prepareWhiteBalance() {
-    uchar4 estimation = estimateWhite();
-    int minimum = min(estimation.r, min(estimation.g, estimation.b));
-    int maximum = max(estimation.r, max(estimation.g, estimation.b));
-    float avg = (minimum + maximum) / 2.f;
-
-    scaleR =  avg/estimation.r;
-    scaleG =  avg/estimation.g;
-    scaleB =  avg/estimation.b;
-
-}
-
-static unsigned char contrastClamp(int c)
-{
-    int N = 255;
-    c &= ~(c >> 31);
-    c -= N;
-    c &= (c >> 31);
-    c += N;
-    return  (unsigned char) c;
-}
-
-void whiteBalanceKernel(const uchar4 *in, uchar4 *out) {
-    float Rc =  in->r*scaleR;
-    float Gc =  in->g*scaleG;
-    float Bc =  in->b*scaleB;
-
-    out->r = contrastClamp(Rc);
-    out->g = contrastClamp(Gc);
-    out->b = contrastClamp(Bc);
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/Android.mk b/tests/RenderScriptTests/ImageProcessing2/Android.mk
deleted file mode 100644
index dc6c0d8..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Copyright (C) 2009 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.support.v8.renderscript
-
-LOCAL_PACKAGE_NAME := ImageProcessing2
-LOCAL_SDK_VERSION := 8
-LOCAL_RENDERSCRIPT_TARGET_API := 17
-LOCAL_RENDERSCRIPT_COMPATIBILITY := 17
-LOCAL_RENDERSCRIPT_INCLUDES_OVERRIDE := $(TOPDIR)external/clang/lib/Headers \
-                                        $(TOPDIR)frameworks/rs/scriptc
-
-LOCAL_RENDERSCRIPT_FLAGS := -rs-package-name=android.support.v8.renderscript
-LOCAL_REQUIRED_MODULES := librsjni
-
-include $(BUILD_PACKAGE)
-
-#include $(call all-makefiles-under, $(LOCAL_PATH))
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
deleted file mode 100644
index 20ee053..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.image2">
-    <uses-sdk android:minSdkVersion="8" />
-    <application android:label="IP GB">
-        <activity android:name="ImageProcessingActivity2">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/city.png b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/city.png
deleted file mode 100644
index 856eeff..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/city.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067.jpg b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067.jpg
deleted file mode 100644
index 05d3ee2..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067b.jpg b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067b.jpg
deleted file mode 100644
index aed0781..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/img1600x1067b.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml
deleted file mode 100644
index f0a2b92..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:id="@+id/toplevel">
-    <SurfaceView
-        android:id="@+id/surface"
-        android:layout_width="1dip"
-        android:layout_height="1dip" />
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="vertical"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
-            <ImageView
-                android:id="@+id/display"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-                    <Button
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/benchmark"
-                        android:onClick="benchmark"/>
-                    <TextView
-                        android:id="@+id/benchmarkText"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/saturation"/>
-            </LinearLayout>
-            <Spinner
-                android:id="@+id/filterselection"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <Spinner
-                android:id="@+id/spinner1"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider1Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/saturation"/>
-             <SeekBar
-                android:id="@+id/slider1"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider2Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/gamma"/>
-            <SeekBar
-                android:id="@+id/slider2"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider3Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:textSize="8pt"
-                android:text="@string/out_white"/>
-            <SeekBar
-                android:id="@+id/slider3"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider4Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/slider4"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider5Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/slider5"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <Button
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/benchmark_all"
-                    android:onClick="benchmark_all"/>
-            </LinearLayout>
-    </ScrollView>
-</LinearLayout>
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/layout/spinner_layout.xml b/tests/RenderScriptTests/ImageProcessing2/res/layout/spinner_layout.xml
deleted file mode 100644
index 8196bbf..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/res/layout/spinner_layout.xml
+++ /dev/null
@@ -1,23 +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"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:padding="10dp"
-    android:textSize="16sp"
-/>
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml
deleted file mode 100644
index a7dd165..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2008 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- General -->
-    <skip />
-    <!--slider label -->
-    <string name="blur_description">Blur Radius</string>
-    <string name="in_white">In White</string>
-    <string name="out_white">Out White</string>
-    <string name="in_black">In Black</string>
-    <string name="out_black">Out Black</string>
-    <string name="gamma">Gamma</string>
-    <string name="saturation">Saturation</string>
-    <string name="benchmark">Benchmark</string>
-    <string name="benchmark_all">Benchmark All</string>
-
-</resources>
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blend.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blend.java
deleted file mode 100644
index ac02101..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blend.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-import java.lang.Short;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.view.View;
-import android.widget.Spinner;
-
-public class Blend extends TestBase {
-    private ScriptIntrinsicBlend mBlend;
-    private ScriptC_blend mBlendHelper;
-    private short image1Alpha = 128;
-    private short image2Alpha = 128;
-
-    String mIntrinsicNames[];
-
-    private Allocation image1;
-    private Allocation image2;
-    private int currentIntrinsic = 0;
-
-    private AdapterView.OnItemSelectedListener mIntrinsicSpinnerListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-                    currentIntrinsic = pos;
-                    runTest();
-                    act.updateDisplay();
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-            };
-
-    public void createTest(android.content.res.Resources res) {
-        mBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS));
-        mBlendHelper = new ScriptC_blend(mRS);
-        mBlendHelper.set_alpha((short)128);
-
-        image1 = Allocation.createTyped(mRS, mInPixelsAllocation.getType());
-        image2 = Allocation.createTyped(mRS, mInPixelsAllocation2.getType());
-
-        mIntrinsicNames = new String[14];
-        mIntrinsicNames[0] = "Source";
-        mIntrinsicNames[1] = "Destination";
-        mIntrinsicNames[2] = "Source Over";
-        mIntrinsicNames[3] = "Destination Over";
-        mIntrinsicNames[4] = "Source In";
-        mIntrinsicNames[5] = "Destination In";
-        mIntrinsicNames[6] = "Source Out";
-        mIntrinsicNames[7] = "Destination Out";
-        mIntrinsicNames[8] = "Source Atop";
-        mIntrinsicNames[9] = "Destination Atop";
-        mIntrinsicNames[10] = "XOR";
-        mIntrinsicNames[11] = "Add";
-        mIntrinsicNames[12] = "Subtract";
-        mIntrinsicNames[13] = "Multiply";
-    }
-
-    public boolean onSpinner1Setup(Spinner s) {
-        s.setAdapter(new ArrayAdapter<String>(
-            act, R.layout.spinner_layout, mIntrinsicNames));
-        s.setOnItemSelectedListener(mIntrinsicSpinnerListener);
-        return true;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Image 1 Alpha");
-        b.setMax(255);
-        b.setProgress(image1Alpha);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        image1Alpha = (short)progress;
-    }
-
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Image 2 Alpha");
-        b.setMax(255);
-        b.setProgress(image2Alpha);
-        return true;
-    }
-
-    public void onBar2Changed(int progress) {
-        image2Alpha = (short)progress;
-    }
-
-    public void runTest() {
-        image1.copy2DRangeFrom(0, 0, mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), mInPixelsAllocation, 0, 0);
-        image2.copy2DRangeFrom(0, 0, mInPixelsAllocation2.getType().getX(), mInPixelsAllocation2.getType().getY(), mInPixelsAllocation2, 0, 0);
-
-        mBlendHelper.set_alpha(image1Alpha);
-        mBlendHelper.forEach_setImageAlpha(image1);
-
-        mBlendHelper.set_alpha(image2Alpha);
-        mBlendHelper.forEach_setImageAlpha(image2);
-
-        switch (currentIntrinsic) {
-        case 0:
-            mBlend.forEachSrc(image1, image2);
-            break;
-        case 1:
-            mBlend.forEachDst(image1, image2);
-            break;
-        case 2:
-            mBlend.forEachSrcOver(image1, image2);
-            break;
-        case 3:
-            mBlend.forEachDstOver(image1, image2);
-            break;
-        case 4:
-            mBlend.forEachSrcIn(image1, image2);
-            break;
-        case 5:
-            mBlend.forEachDstIn(image1, image2);
-            break;
-        case 6:
-            mBlend.forEachSrcOut(image1, image2);
-            break;
-        case 7:
-            mBlend.forEachDstOut(image1, image2);
-            break;
-        case 8:
-            mBlend.forEachSrcAtop(image1, image2);
-            break;
-        case 9:
-            mBlend.forEachDstAtop(image1, image2);
-            break;
-        case 10:
-            mBlend.forEachXor(image1, image2);
-            break;
-        case 11:
-            mBlend.forEachAdd(image1, image2);
-            break;
-        case 12:
-            mBlend.forEachSubtract(image1, image2);
-            break;
-        case 13:
-            mBlend.forEachMultiply(image1, image2);
-            break;
-        }
-
-        mOutPixelsAllocation.copy2DRangeFrom(0, 0, image2.getType().getX(), image2.getType().getY(), image2, 0, 0);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java
deleted file mode 100644
index b518b02..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Blur25 extends TestBase {
-    private boolean mUseIntrinsic = false;
-    private ScriptIntrinsicBlur mIntrinsic;
-
-    private int MAX_RADIUS = 25;
-    private ScriptC_threshold mScript;
-    private float mRadius = MAX_RADIUS;
-    private float mSaturation = 1.0f;
-    private Allocation mScratchPixelsAllocation1;
-    private Allocation mScratchPixelsAllocation2;
-
-
-    public Blur25(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Radius");
-        b.setProgress(100);
-        return true;
-    }
-
-
-    public void onBar1Changed(int progress) {
-        mRadius = ((float)progress) / 100.0f * MAX_RADIUS;
-        if (mRadius <= 0.10f) {
-            mRadius = 0.10f;
-        }
-        if (mUseIntrinsic) {
-            mIntrinsic.setRadius(mRadius);
-        } else {
-            mScript.invoke_setRadius((int)mRadius);
-        }
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setRadius(MAX_RADIUS);
-            mIntrinsic.setInput(mInPixelsAllocation);
-        } else {
-
-            Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
-            tb.setX(width);
-            tb.setY(height);
-            mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
-            mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
-
-            mScript = new ScriptC_threshold(mRS, res, R.raw.threshold);
-            mScript.set_width(width);
-            mScript.set_height(height);
-            mScript.invoke_setRadius(MAX_RADIUS);
-
-            mScript.set_InPixel(mInPixelsAllocation);
-            mScript.set_ScratchPixel1(mScratchPixelsAllocation1);
-            mScript.set_ScratchPixel2(mScratchPixelsAllocation2);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mOutPixelsAllocation);
-        } else {
-            mScript.forEach_copyIn(mInPixelsAllocation, mScratchPixelsAllocation1);
-            mScript.forEach_horz(mScratchPixelsAllocation2);
-            mScript.forEach_vert(mOutPixelsAllocation);
-        }
-    }
-
-    public void setupBenchmark() {
-        if (mUseIntrinsic) {
-            mIntrinsic.setRadius(MAX_RADIUS);
-        } else {
-            mScript.invoke_setRadius(MAX_RADIUS);
-        }
-    }
-
-    public void exitBenchmark() {
-        if (mUseIntrinsic) {
-            mIntrinsic.setRadius(mRadius);
-        } else {
-            mScript.invoke_setRadius((int)mRadius);
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ColorMatrix.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ColorMatrix.java
deleted file mode 100644
index 3b0f86a..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ColorMatrix.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class ColorMatrix extends TestBase {
-    private ScriptC_colormatrix mScript;
-    private ScriptIntrinsicColorMatrix mIntrinsic;
-    private boolean mUseIntrinsic;
-    private boolean mUseGrey;
-
-    public ColorMatrix(boolean useIntrinsic, boolean useGrey) {
-        mUseIntrinsic = useIntrinsic;
-        mUseGrey = useGrey;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        Matrix4f m = new Matrix4f();
-        m.set(1, 0, 0.2f);
-        m.set(1, 1, 0.9f);
-        m.set(1, 2, 0.2f);
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
-            if (mUseGrey) {
-                mIntrinsic.setGreyscale();
-            } else {
-                mIntrinsic.setColorMatrix(m);
-            }
-        } else {
-            mScript = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
-            mScript.invoke_setMatrix(m);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve3x3.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve3x3.java
deleted file mode 100644
index d4852f0..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve3x3.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class Convolve3x3 extends TestBase {
-    private ScriptC_ip2_convolve3x3 mScript;
-    private ScriptIntrinsicConvolve3x3 mIntrinsic;
-
-    private int mWidth;
-    private int mHeight;
-    private boolean mUseIntrinsic;
-
-    public Convolve3x3(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        float f[] = new float[9];
-        f[0] =  0.f;    f[1] = -1.f;    f[2] =  0.f;
-        f[3] = -1.f;    f[4] =  5.f;    f[5] = -1.f;
-        f[6] =  0.f;    f[7] = -1.f;    f[8] =  0.f;
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setCoefficients(f);
-            mIntrinsic.setInput(mInPixelsAllocation);
-        } else {
-            mScript = new ScriptC_ip2_convolve3x3(mRS, res, R.raw.ip2_convolve3x3);
-            mScript.set_gCoeffs(f);
-            mScript.set_gIn(mInPixelsAllocation);
-            mScript.set_gWidth(mWidth);
-            mScript.set_gHeight(mHeight);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve5x5.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve5x5.java
deleted file mode 100644
index d2da3c4..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Convolve5x5.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class Convolve5x5 extends TestBase {
-    private ScriptC_convolve5x5 mScript;
-    private ScriptIntrinsicConvolve5x5 mIntrinsic;
-
-    private int mWidth;
-    private int mHeight;
-    private boolean mUseIntrinsic;
-
-    public Convolve5x5(boolean useIntrinsic) {
-        mUseIntrinsic = useIntrinsic;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        float f[] = new float[25];
-        //f[0] = 0.012f; f[1] = 0.025f; f[2] = 0.031f; f[3] = 0.025f; f[4] = 0.012f;
-        //f[5] = 0.025f; f[6] = 0.057f; f[7] = 0.075f; f[8] = 0.057f; f[9] = 0.025f;
-        //f[10]= 0.031f; f[11]= 0.075f; f[12]= 0.095f; f[13]= 0.075f; f[14]= 0.031f;
-        //f[15]= 0.025f; f[16]= 0.057f; f[17]= 0.075f; f[18]= 0.057f; f[19]= 0.025f;
-        //f[20]= 0.012f; f[21]= 0.025f; f[22]= 0.031f; f[23]= 0.025f; f[24]= 0.012f;
-
-        //f[0] = 1.f; f[1] = 2.f; f[2] = 0.f; f[3] = -2.f; f[4] = -1.f;
-        //f[5] = 4.f; f[6] = 8.f; f[7] = 0.f; f[8] = -8.f; f[9] = -4.f;
-        //f[10]= 6.f; f[11]=12.f; f[12]= 0.f; f[13]=-12.f; f[14]= -6.f;
-        //f[15]= 4.f; f[16]= 8.f; f[17]= 0.f; f[18]= -8.f; f[19]= -4.f;
-        //f[20]= 1.f; f[21]= 2.f; f[22]= 0.f; f[23]= -2.f; f[24]= -1.f;
-
-        f[0] = -1.f; f[1] = -3.f; f[2] = -4.f; f[3] = -3.f; f[4] = -1.f;
-        f[5] = -3.f; f[6] =  0.f; f[7] =  6.f; f[8] =  0.f; f[9] = -3.f;
-        f[10]= -4.f; f[11]=  6.f; f[12]= 20.f; f[13]=  6.f; f[14]= -4.f;
-        f[15]= -3.f; f[16]=  0.f; f[17]=  6.f; f[18]=  0.f; f[19]= -3.f;
-        f[20]= -1.f; f[21]= -3.f; f[22]= -4.f; f[23]= -3.f; f[24]= -1.f;
-
-        if (mUseIntrinsic) {
-            mIntrinsic = ScriptIntrinsicConvolve5x5.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setCoefficients(f);
-            mIntrinsic.setInput(mInPixelsAllocation);
-        } else {
-            mScript = new ScriptC_convolve5x5(mRS, res, R.raw.convolve5x5);
-            mScript.set_gCoeffs(f);
-            mScript.set_gIn(mInPixelsAllocation);
-            mScript.set_gWidth(mWidth);
-            mScript.set_gHeight(mHeight);
-        }
-    }
-
-    public void runTest() {
-        if (mUseIntrinsic) {
-            mIntrinsic.forEach(mOutPixelsAllocation);
-        } else {
-            mScript.forEach_root(mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Copy.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Copy.java
deleted file mode 100644
index ef71907..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Copy.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class Copy extends TestBase {
-    private ScriptC_copy mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_copy(mRS, res, R.raw.copy);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/CrossProcess.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/CrossProcess.java
deleted file mode 100644
index 96787d7..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/CrossProcess.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class CrossProcess extends TestBase {
-    private ScriptIntrinsicLUT mIntrinsic;
-
-    public void createTest(android.content.res.Resources res) {
-        mIntrinsic = ScriptIntrinsicLUT.create(mRS, Element.U8_4(mRS));
-        for (int ct=0; ct < 256; ct++) {
-            float f = ((float)ct) / 255.f;
-
-            float r = f;
-            if (r < 0.5f) {
-                r = 4.0f * r * r * r;
-            } else {
-                r = 1.0f - r;
-                r = 1.0f - (4.0f * r * r * r);
-            }
-            mIntrinsic.setRed(ct, (int)(r * 255.f + 0.5f));
-
-            float g = f;
-            if (g < 0.5f) {
-                g = 2.0f * g * g;
-            } else {
-                g = 1.0f - g;
-                g = 1.0f - (2.0f * g * g);
-            }
-            mIntrinsic.setGreen(ct, (int)(g * 255.f + 0.5f));
-
-            float b = f * 0.5f + 0.25f;
-            mIntrinsic.setBlue(ct, (int)(b * 255.f + 0.5f));
-        }
-
-    }
-
-    public void runTest() {
-        mIntrinsic.forEach(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java
deleted file mode 100644
index 97beb88..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import android.support.v8.renderscript.*;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Fisheye extends TestBase {
-    private ScriptC_fisheye_full mScript_full = null;
-    private ScriptC_fisheye_relaxed mScript_relaxed = null;
-    private ScriptC_fisheye_approx_full mScript_approx_full = null;
-    private ScriptC_fisheye_approx_relaxed mScript_approx_relaxed = null;
-    private final boolean approx;
-    private final boolean relaxed;
-    private float center_x = 0.5f;
-    private float center_y = 0.5f;
-    private float scale = 0.5f;
-
-    public Fisheye(boolean approx, boolean relaxed) {
-        this.approx = approx;
-        this.relaxed = relaxed;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Scale");
-        b.setMax(100);
-        b.setProgress(25);
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Shift center X");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Shift center Y");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        scale = progress / 50.0f;
-        do_init();
-    }
-    public void onBar2Changed(int progress) {
-        center_x = progress / 100.0f;
-        do_init();
-    }
-    public void onBar3Changed(int progress) {
-        center_y = progress / 100.0f;
-        do_init();
-    }
-
-    private void do_init() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.invoke_init_filter(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale);
-            else
-                mScript_approx_full.invoke_init_filter(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale);
-        } else if (relaxed)
-            mScript_relaxed.invoke_init_filter(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale);
-        else
-            mScript_full.invoke_init_filter(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        if (approx) {
-            if (relaxed) {
-                mScript_approx_relaxed = new ScriptC_fisheye_approx_relaxed(mRS,
-                        res, R.raw.fisheye_approx_relaxed);
-                mScript_approx_relaxed.set_in_alloc(mInPixelsAllocation);
-                mScript_approx_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-            } else {
-                mScript_approx_full = new ScriptC_fisheye_approx_full(mRS, res,
-                        R.raw.fisheye_approx_full);
-                mScript_approx_full.set_in_alloc(mInPixelsAllocation);
-                mScript_approx_full.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-            }
-        } else if (relaxed) {
-            mScript_relaxed = new ScriptC_fisheye_relaxed(mRS, res,
-                    R.raw.fisheye_relaxed);
-            mScript_relaxed.set_in_alloc(mInPixelsAllocation);
-            mScript_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-        } else {
-            mScript_full = new ScriptC_fisheye_full(mRS, res,
-                    R.raw.fisheye_full);
-            mScript_full.set_in_alloc(mInPixelsAllocation);
-            mScript_full.set_sampler(Sampler.CLAMP_LINEAR(mRS));
-        }
-        do_init();
-    }
-
-    public void runTest() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.forEach_root(mOutPixelsAllocation);
-            else
-                mScript_approx_full.forEach_root(mOutPixelsAllocation);
-        } else if (relaxed)
-            mScript_relaxed.forEach_root(mOutPixelsAllocation);
-        else
-            mScript_full.forEach_root(mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java
deleted file mode 100644
index dfd3c32..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Grain extends TestBase {
-    private ScriptC_grain mScript;
-    private Allocation mNoise;
-    private Allocation mNoise2;
-
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Strength");
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        float s = progress / 100.0f;
-        mScript.set_gNoiseStrength(s);
-    }
-
-    private int findHighBit(int v) {
-        int bit = 0;
-        while (v > 1) {
-            bit++;
-            v >>= 1;
-        }
-        return bit;
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        int noiseW = findHighBit(width);
-        int noiseH = findHighBit(height);
-        if (noiseW > 9) {
-            noiseW = 9;
-        }
-        if (noiseH > 9) {
-            noiseH = 9;
-        }
-        noiseW = 1 << noiseW;
-        noiseH = 1 << noiseH;
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS));
-        tb.setX(noiseW);
-        tb.setY(noiseH);
-        mNoise = Allocation.createTyped(mRS, tb.create());
-        mNoise2 = Allocation.createTyped(mRS, tb.create());
-
-        mScript = new ScriptC_grain(mRS, res, R.raw.grain);
-        mScript.set_gWMask(noiseW - 1);
-        mScript.set_gHMask(noiseH - 1);
-        mScript.set_gNoiseStrength(0.5f);
-        mScript.set_gBlendSource(mNoise);
-        mScript.set_gNoise(mNoise2);
-    }
-
-    public void runTest() {
-        mScript.forEach_genRand(mNoise);
-        mScript.forEach_blend9(mNoise2);
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Greyscale.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Greyscale.java
deleted file mode 100644
index 2d85ae7..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Greyscale.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class Greyscale extends TestBase {
-    private ScriptC_greyscale mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_greyscale(mRS, res, R.raw.greyscale);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java
deleted file mode 100644
index a7ceebe..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class GroupTest extends TestBase {
-    private ScriptIntrinsicConvolve3x3 mConvolve;
-    private ScriptIntrinsicColorMatrix mMatrix;
-
-    private Allocation mScratchPixelsAllocation1;
-    private ScriptGroup mGroup;
-
-    private int mWidth;
-    private int mHeight;
-    private boolean mUseNative;
-
-
-    public GroupTest(boolean useNative) {
-        mUseNative = useNative;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        mConvolve = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS));
-        mMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
-
-        float f[] = new float[9];
-        f[0] =  0.f;    f[1] = -1.f;    f[2] =  0.f;
-        f[3] = -1.f;    f[4] =  5.f;    f[5] = -1.f;
-        f[6] =  0.f;    f[7] = -1.f;    f[8] =  0.f;
-        mConvolve.setCoefficients(f);
-
-        Matrix4f m = new Matrix4f();
-        m.set(1, 0, 0.2f);
-        m.set(1, 1, 0.9f);
-        m.set(1, 2, 0.2f);
-        mMatrix.setColorMatrix(m);
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8_4(mRS));
-        tb.setX(mWidth);
-        tb.setY(mHeight);
-        Type connect = tb.create();
-
-        if (mUseNative) {
-            ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
-            b.addKernel(mConvolve.getKernelID());
-            b.addKernel(mMatrix.getKernelID());
-            b.addConnection(connect, mConvolve.getKernelID(), mMatrix.getKernelID());
-            mGroup = b.create();
-        } else {
-            mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect);
-        }
-    }
-
-    public void runTest() {
-        mConvolve.setInput(mInPixelsAllocation);
-        if (mUseNative) {
-            mGroup.setOutput(mMatrix.getKernelID(), mOutPixelsAllocation);
-            mGroup.execute();
-        } else {
-            mConvolve.forEach(mScratchPixelsAllocation1);
-            mMatrix.forEach(mScratchPixelsAllocation1, mOutPixelsAllocation);
-        }
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java
deleted file mode 100644
index 19bea43..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.support.v8.renderscript.*;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.view.View;
-import android.util.Log;
-import java.lang.Math;
-
-import android.os.Environment;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-public class ImageProcessingActivity2 extends Activity
-                                       implements SeekBar.OnSeekBarChangeListener {
-    private final String TAG = "Img";
-    private final String RESULT_FILE = "image_processing_result.csv";
-
-    Bitmap mBitmapIn;
-    Bitmap mBitmapIn2;
-    Bitmap mBitmapOut;
-    String mTestNames[];
-
-    private Spinner mSpinner;
-    private SeekBar mBar1;
-    private SeekBar mBar2;
-    private SeekBar mBar3;
-    private SeekBar mBar4;
-    private SeekBar mBar5;
-    private TextView mText1;
-    private TextView mText2;
-    private TextView mText3;
-    private TextView mText4;
-    private TextView mText5;
-
-    private float mSaturation = 1.0f;
-
-    private TextView mBenchmarkResult;
-    private Spinner mTestSpinner;
-
-    private SurfaceView mSurfaceView;
-    private ImageView mDisplayView;
-
-    private boolean mDoingBenchmark;
-
-    private TestBase mTest;
-
-    public void updateDisplay() {
-            mTest.updateBitmap(mBitmapOut);
-            mDisplayView.invalidate();
-    }
-
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        if (fromUser) {
-
-            if (seekBar == mBar1) {
-                mTest.onBar1Changed(progress);
-            } else if (seekBar == mBar2) {
-                mTest.onBar2Changed(progress);
-            } else if (seekBar == mBar3) {
-                mTest.onBar3Changed(progress);
-            } else if (seekBar == mBar4) {
-                mTest.onBar4Changed(progress);
-            } else if (seekBar == mBar5) {
-                mTest.onBar5Changed(progress);
-            }
-
-            mTest.runTest();
-            updateDisplay();
-        }
-    }
-
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-    }
-
-    void setupBars() {
-        mSpinner.setVisibility(View.VISIBLE);
-        mTest.onSpinner1Setup(mSpinner);
-
-        mBar1.setVisibility(View.VISIBLE);
-        mText1.setVisibility(View.VISIBLE);
-        mTest.onBar1Setup(mBar1, mText1);
-
-        mBar2.setVisibility(View.VISIBLE);
-        mText2.setVisibility(View.VISIBLE);
-        mTest.onBar2Setup(mBar2, mText2);
-
-        mBar3.setVisibility(View.VISIBLE);
-        mText3.setVisibility(View.VISIBLE);
-        mTest.onBar3Setup(mBar3, mText3);
-
-        mBar4.setVisibility(View.VISIBLE);
-        mText4.setVisibility(View.VISIBLE);
-        mTest.onBar4Setup(mBar4, mText4);
-
-        mBar5.setVisibility(View.VISIBLE);
-        mText5.setVisibility(View.VISIBLE);
-        mTest.onBar5Setup(mBar5, mText5);
-    }
-
-
-    void changeTest(int testID) {
-        if (mTest != null) {
-            mTest.destroy();
-        }
-        switch(testID) {
-        case 0:
-            mTest = new LevelsV4(false, false);
-            break;
-        case 1:
-            mTest = new LevelsV4(false, true);
-            break;
-        case 2:
-            mTest = new LevelsV4(true, false);
-            break;
-        case 3:
-            mTest = new LevelsV4(true, true);
-            break;
-        case 4:
-            mTest = new Blur25(false);
-            break;
-        case 5:
-            mTest = new Blur25(true);
-            break;
-        case 6:
-            mTest = new Greyscale();
-            break;
-        case 7:
-            mTest = new Grain();
-            break;
-        case 8:
-            mTest = new Fisheye(false, false);
-            break;
-        case 9:
-            mTest = new Fisheye(false, true);
-            break;
-        case 10:
-            mTest = new Fisheye(true, false);
-            break;
-        case 11:
-            mTest = new Fisheye(true, true);
-            break;
-        case 12:
-            mTest = new Vignette(false, false);
-            break;
-        case 13:
-            mTest = new Vignette(false, true);
-            break;
-        case 14:
-            mTest = new Vignette(true, false);
-            break;
-        case 15:
-            mTest = new Vignette(true, true);
-            break;
-        case 16:
-            mTest = new GroupTest(false);
-            break;
-        case 17:
-            mTest = new GroupTest(true);
-            break;
-        case 18:
-            mTest = new Convolve3x3(false);
-            break;
-        case 19:
-            mTest = new Convolve3x3(true);
-            break;
-        case 20:
-            mTest = new ColorMatrix(false, false);
-            break;
-        case 21:
-            mTest = new ColorMatrix(true, false);
-            break;
-        case 22:
-            mTest = new ColorMatrix(true, true);
-            break;
-        case 23:
-            mTest = new Copy();
-            break;
-        case 24:
-            mTest = new CrossProcess();
-            break;
-        case 25:
-            mTest = new Convolve5x5(false);
-            break;
-        case 26:
-            mTest = new Convolve5x5(true);
-            break;
-        case 27:
-            mTest = new Mandelbrot();
-            break;
-        case 28:
-            mTest = new Blend();
-            break;
-        }
-
-        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2, mBitmapOut);
-        setupBars();
-
-        mTest.runTest();
-        updateDisplay();
-        mBenchmarkResult.setText("Result: not run");
-    }
-
-    void setupTests() {
-        mTestNames = new String[29];
-        mTestNames[0] = "Levels Vec3 Relaxed";
-        mTestNames[1] = "Levels Vec4 Relaxed";
-        mTestNames[2] = "Levels Vec3 Full";
-        mTestNames[3] = "Levels Vec4 Full";
-        mTestNames[4] = "Blur radius 25";
-        mTestNames[5] = "Intrinsic Blur radius 25";
-        mTestNames[6] = "Greyscale";
-        mTestNames[7] = "Grain";
-        mTestNames[8] = "Fisheye Full";
-        mTestNames[9] = "Fisheye Relaxed";
-        mTestNames[10] = "Fisheye Approximate Full";
-        mTestNames[11] = "Fisheye Approximate Relaxed";
-        mTestNames[12] = "Vignette Full";
-        mTestNames[13] = "Vignette Relaxed";
-        mTestNames[14] = "Vignette Approximate Full";
-        mTestNames[15] = "Vignette Approximate Relaxed";
-        mTestNames[16] = "Group Test (emulated)";
-        mTestNames[17] = "Group Test (native)";
-        mTestNames[18] = "Convolve 3x3";
-        mTestNames[19] = "Intrinsics Convolve 3x3";
-        mTestNames[20] = "ColorMatrix";
-        mTestNames[21] = "Intrinsics ColorMatrix";
-        mTestNames[22] = "Intrinsics ColorMatrix Grey";
-        mTestNames[23] = "Copy";
-        mTestNames[24] = "CrossProcess (using LUT)";
-        mTestNames[25] = "Convolve 5x5";
-        mTestNames[26] = "Intrinsics Convolve 5x5";
-        mTestNames[27] = "Mandelbrot";
-        mTestNames[28] = "Intrinsics Blend";
-
-        mTestSpinner.setAdapter(new ArrayAdapter<String>(
-            this, R.layout.spinner_layout, mTestNames));
-    }
-
-    private AdapterView.OnItemSelectedListener mTestSpinnerListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-                    changeTest(pos);
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-            };
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        mBitmapIn = loadBitmap(R.drawable.img1600x1067);
-        mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b);
-        mBitmapOut = loadBitmap(R.drawable.img1600x1067);
-
-        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
-
-        mDisplayView = (ImageView) findViewById(R.id.display);
-        mDisplayView.setImageBitmap(mBitmapOut);
-
-        mSpinner = (Spinner) findViewById(R.id.spinner1);
-
-        mBar1 = (SeekBar) findViewById(R.id.slider1);
-        mBar2 = (SeekBar) findViewById(R.id.slider2);
-        mBar3 = (SeekBar) findViewById(R.id.slider3);
-        mBar4 = (SeekBar) findViewById(R.id.slider4);
-        mBar5 = (SeekBar) findViewById(R.id.slider5);
-
-        mBar1.setOnSeekBarChangeListener(this);
-        mBar2.setOnSeekBarChangeListener(this);
-        mBar3.setOnSeekBarChangeListener(this);
-        mBar4.setOnSeekBarChangeListener(this);
-        mBar5.setOnSeekBarChangeListener(this);
-
-        mText1 = (TextView) findViewById(R.id.slider1Text);
-        mText2 = (TextView) findViewById(R.id.slider2Text);
-        mText3 = (TextView) findViewById(R.id.slider3Text);
-        mText4 = (TextView) findViewById(R.id.slider4Text);
-        mText5 = (TextView) findViewById(R.id.slider5Text);
-
-        mTestSpinner = (Spinner) findViewById(R.id.filterselection);
-        mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
-
-        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
-        mBenchmarkResult.setText("Result: not run");
-
-        setupTests();
-        changeTest(0);
-    }
-
-
-    private Bitmap loadBitmap(int resource) {
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        return copyBitmap(BitmapFactory.decodeResource(getResources(), resource, options));
-    }
-
-    private static Bitmap copyBitmap(Bitmap source) {
-        Bitmap b = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());
-        Canvas c = new Canvas(b);
-        c.drawBitmap(source, 0, 0, null);
-        source.recycle();
-        return b;
-    }
-
-    // button hook
-    public void benchmark(View v) {
-        float t = getBenchmark();
-        //long javaTime = javaFilter();
-        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
-        mBenchmarkResult.setText("Result: " + t + " ms");
-        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
-    }
-
-    public void benchmark_all(View v) {
-        // write result into a file
-        File externalStorage = Environment.getExternalStorageDirectory();
-        if (!externalStorage.canWrite()) {
-            Log.v(TAG, "sdcard is not writable");
-            return;
-        }
-        File resultFile = new File(externalStorage, RESULT_FILE);
-        //resultFile.setWritable(true, false);
-        try {
-            BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile));
-            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
-            for (int i = 0; i < mTestNames.length; i++ ) {
-                changeTest(i);
-                float t = getBenchmark();
-                String s = new String("" + mTestNames[i] + ", " + t);
-                rsWriter.write(s + "\n");
-                Log.v(TAG, "Test " + s + "ms\n");
-            }
-            rsWriter.close();
-        } catch (IOException e) {
-            Log.v(TAG, "Unable to write result file " + e.getMessage());
-        }
-        changeTest(0);
-    }
-
-    // For benchmark test
-    public float getBenchmark() {
-        mDoingBenchmark = true;
-
-        mTest.setupBenchmark();
-        long result = 0;
-
-        //Log.v(TAG, "Warming");
-        long t = java.lang.System.currentTimeMillis() + 250;
-        do {
-            mTest.runTest();
-            mTest.finish();
-        } while (t > java.lang.System.currentTimeMillis());
-
-
-        //Log.v(TAG, "Benchmarking");
-        int ct = 0;
-        t = java.lang.System.currentTimeMillis();
-        do {
-            mTest.runTest();
-            mTest.finish();
-            ct++;
-        } while ((t+1000) > java.lang.System.currentTimeMillis());
-        t = java.lang.System.currentTimeMillis() - t;
-        float ft = (float)t;
-        ft /= ct;
-
-        mTest.exitBenchmark();
-        mDoingBenchmark = false;
-
-        return ft;
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/LevelsV4.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/LevelsV4.java
deleted file mode 100644
index fbe3727..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/LevelsV4.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-
-public class LevelsV4 extends TestBase {
-    private ScriptC_levels_relaxed mScriptR;
-    private ScriptC_levels_full mScriptF;
-    private float mInBlack = 0.0f;
-    private float mOutBlack = 0.0f;
-    private float mInWhite = 255.0f;
-    private float mOutWhite = 255.0f;
-    private float mSaturation = 1.0f;
-
-    Matrix3f satMatrix = new Matrix3f();
-    float mInWMinInB;
-    float mOutWMinOutB;
-    float mOverInWMinInB;
-
-    boolean mUseFull;
-    boolean mUseV4;
-
-    LevelsV4(boolean useFull, boolean useV4) {
-        mUseFull = useFull;
-        mUseV4 = useV4;
-    }
-
-
-    private void setLevels() {
-        mInWMinInB = mInWhite - mInBlack;
-        mOutWMinOutB = mOutWhite - mOutBlack;
-        mOverInWMinInB = 1.f / mInWMinInB;
-
-        mScriptR.set_inBlack(mInBlack);
-        mScriptR.set_outBlack(mOutBlack);
-        mScriptR.set_inWMinInB(mInWMinInB);
-        mScriptR.set_outWMinOutB(mOutWMinOutB);
-        mScriptR.set_overInWMinInB(mOverInWMinInB);
-        mScriptF.set_inBlack(mInBlack);
-        mScriptF.set_outBlack(mOutBlack);
-        mScriptF.set_inWMinInB(mInWMinInB);
-        mScriptF.set_outWMinOutB(mOutWMinOutB);
-        mScriptF.set_overInWMinInB(mOverInWMinInB);
-    }
-
-    private void setSaturation() {
-        float rWeight = 0.299f;
-        float gWeight = 0.587f;
-        float bWeight = 0.114f;
-        float oneMinusS = 1.0f - mSaturation;
-
-        satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
-        satMatrix.set(0, 1, oneMinusS * rWeight);
-        satMatrix.set(0, 2, oneMinusS * rWeight);
-        satMatrix.set(1, 0, oneMinusS * gWeight);
-        satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
-        satMatrix.set(1, 2, oneMinusS * gWeight);
-        satMatrix.set(2, 0, oneMinusS * bWeight);
-        satMatrix.set(2, 1, oneMinusS * bWeight);
-        satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
-        mScriptR.set_colorMat(satMatrix);
-        mScriptF.set_colorMat(satMatrix);
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        b.setProgress(50);
-        t.setText("Saturation");
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(0);
-        t.setText("In Black");
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(0);
-        t.setText("Out Black");
-        return true;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(128);
-        t.setText("Out White");
-        return true;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(128);
-        t.setText("Out White");
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        mSaturation = (float)progress / 50.0f;
-        setSaturation();
-    }
-    public void onBar2Changed(int progress) {
-        mInBlack = (float)progress;
-        setLevels();
-    }
-    public void onBar3Changed(int progress) {
-        mOutBlack = (float)progress;
-        setLevels();
-    }
-    public void onBar4Changed(int progress) {
-        mInWhite = (float)progress + 127.0f;
-        setLevels();
-    }
-    public void onBar5Changed(int progress) {
-        mOutWhite = (float)progress + 127.0f;
-        setLevels();
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mScriptR = new ScriptC_levels_relaxed(mRS, res, R.raw.levels_relaxed);
-        mScriptF = new ScriptC_levels_full(mRS, res, R.raw.levels_full);
-        setSaturation();
-        setLevels();
-    }
-
-    public void runTest() {
-        if (mUseFull) {
-            if (mUseV4) {
-                mScriptF.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
-            } else {
-                mScriptF.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-            }
-        } else {
-            if (mUseV4) {
-                mScriptR.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
-            } else {
-                mScriptR.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-            }
-        }
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Mandelbrot.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Mandelbrot.java
deleted file mode 100644
index 556d797..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Mandelbrot.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import java.lang.Math;
-
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Mandelbrot extends TestBase {
-    private ScriptC_mandelbrot mScript;
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Iterations");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        int iters = progress * 3 + 50;
-        mScript.set_gMaxIteration(iters);
-    }
-
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Lower Bound: X");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar2Changed(int progress) {
-        float scaleFactor = mScript.get_scaleFactor();
-        // allow viewport to be moved by 2x scale factor
-        float lowerBoundX = -2.f + ((progress / scaleFactor) / 50.f);
-        mScript.set_lowerBoundX(lowerBoundX);
-    }
-
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Lower Bound: Y");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar3Changed(int progress) {
-        float scaleFactor = mScript.get_scaleFactor();
-        // allow viewport to be moved by 2x scale factor
-        float lowerBoundY = -2.f + ((progress / scaleFactor) / 50.f);
-        mScript.set_lowerBoundY(lowerBoundY);
-    }
-
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        t.setText("Scale Factor");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar4Changed(int progress) {
-        float scaleFactor = 4.f - (3.96f * (progress / 100.f));
-        mScript.set_scaleFactor(scaleFactor);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mOutPixelsAllocation.getType().getX();
-        int height = mOutPixelsAllocation.getType().getY();
-
-        mScript = new ScriptC_mandelbrot(mRS, res, R.raw.mandelbrot);
-        mScript.set_gDimX(width);
-        mScript.set_gDimY(height);
-        mScript.set_gMaxIteration(50);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mOutPixelsAllocation);
-        mRS.finish();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java
deleted file mode 100644
index dbbc594..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.support.v8.renderscript.*;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.view.View;
-import android.util.Log;
-import java.lang.Math;
-import android.widget.Spinner;
-
-public class TestBase  {
-    protected final String TAG = "Img";
-
-    protected RenderScript mRS;
-    protected Allocation mInPixelsAllocation;
-    protected Allocation mInPixelsAllocation2;
-    protected Allocation mOutPixelsAllocation;
-
-    protected ImageProcessingActivity2 act;
-
-    // Override to use UI elements
-    public void onBar1Changed(int progress) {
-    }
-    public void onBar2Changed(int progress) {
-    }
-    public void onBar3Changed(int progress) {
-    }
-    public void onBar4Changed(int progress) {
-    }
-    public void onBar5Changed(int progress) {
-    }
-
-    // Override to use UI elements
-    // Unused bars will be hidden.
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-
-    public boolean onSpinner1Setup(Spinner s) {
-        s.setVisibility(View.INVISIBLE);
-        return false;
-    }
-
-    public final void createBaseTest(ImageProcessingActivity2 ipact, Bitmap b, Bitmap b2, Bitmap outb) {
-        act = ipact;
-        mRS = RenderScript.create(act);
-
-        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b);
-        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, outb);
-
-        createTest(act.getResources());
-    }
-
-    // Must override
-    public void createTest(android.content.res.Resources res) {
-        android.util.Log.e("img", "implement createTest");
-    }
-
-    // Must override
-    public void runTest() {
-    }
-
-    public void finish() {
-        mRS.finish();
-    }
-
-    public void destroy() {
-        mRS.destroy();
-    }
-
-    public void updateBitmap(Bitmap b) {
-        mOutPixelsAllocation.copyTo(b);
-    }
-
-    // Override to configure specific benchmark config.
-    public void setupBenchmark() {
-    }
-
-    // Override to reset after benchmark.
-    public void exitBenchmark() {
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java
deleted file mode 100644
index 8618d5a..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.image2;
-
-import android.support.v8.renderscript.*;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Vignette extends TestBase {
-    private ScriptC_vignette_full mScript_full = null;
-    private ScriptC_vignette_relaxed mScript_relaxed = null;
-    private ScriptC_vignette_approx_full mScript_approx_full = null;
-    private ScriptC_vignette_approx_relaxed mScript_approx_relaxed = null;
-    private final boolean approx;
-    private final boolean relaxed;
-    private float center_x = 0.5f;
-    private float center_y = 0.5f;
-    private float scale = 0.5f;
-    private float shade = 0.5f;
-    private float slope = 20.0f;
-
-    public Vignette(boolean approx, boolean relaxed) {
-        this.approx = approx;
-        this.relaxed = relaxed;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Scale");
-        b.setMax(100);
-        b.setProgress(25);
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Shade");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Slope");
-        b.setMax(100);
-        b.setProgress(20);
-        return true;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        t.setText("Shift center X");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        t.setText("Shift center Y");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        scale = progress / 50.0f;
-        do_init();
-    }
-    public void onBar2Changed(int progress) {
-        shade = progress / 100.0f;
-        do_init();
-    }
-    public void onBar3Changed(int progress) {
-        slope = (float)progress;
-        do_init();
-    }
-    public void onBar4Changed(int progress) {
-        center_x = progress / 100.0f;
-        do_init();
-    }
-    public void onBar5Changed(int progress) {
-        center_y = progress / 100.0f;
-        do_init();
-    }
-
-    private void do_init() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.invoke_init_vignette(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale, shade, slope);
-            else
-                mScript_approx_full.invoke_init_vignette(
-                        mInPixelsAllocation.getType().getX(),
-                        mInPixelsAllocation.getType().getY(), center_x,
-                        center_y, scale, shade, slope);
-        } else if (relaxed)
-            mScript_relaxed.invoke_init_vignette(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale, shade, slope);
-        else
-            mScript_full.invoke_init_vignette(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale, shade, slope);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed = new ScriptC_vignette_approx_relaxed(
-                        mRS, res, R.raw.vignette_approx_relaxed);
-            else
-                mScript_approx_full = new ScriptC_vignette_approx_full(
-                        mRS, res, R.raw.vignette_approx_full);
-        } else if (relaxed)
-            mScript_relaxed = new ScriptC_vignette_relaxed(mRS, res,
-                    R.raw.vignette_relaxed);
-        else
-            mScript_full = new ScriptC_vignette_full(mRS, res,
-                    R.raw.vignette_full);
-        do_init();
-    }
-
-    public void runTest() {
-        if (approx) {
-            if (relaxed)
-                mScript_approx_relaxed.forEach_root(mInPixelsAllocation,
-                        mOutPixelsAllocation);
-            else
-                mScript_approx_full.forEach_root(mInPixelsAllocation,
-                        mOutPixelsAllocation);
-        } else if (relaxed)
-            mScript_relaxed.forEach_root(mInPixelsAllocation,
-                    mOutPixelsAllocation);
-        else
-            mScript_full.forEach_root(mInPixelsAllocation,
-                    mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/blend.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/blend.rs
deleted file mode 100644
index 4d90725..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/blend.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2011 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-uchar alpha = 0x0;
-
-void setImageAlpha(uchar4 *v_out, uint32_t x, uint32_t y) {
-  v_out->rgba = convert_uchar4((convert_uint4(v_out->rgba) * alpha) >> (uint4)8);
-  v_out->a = alpha;
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/colormatrix.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/colormatrix.rs
deleted file mode 100644
index e93bef3..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/colormatrix.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-
-static rs_matrix4x4 Mat;
-
-void init() {
-    rsMatrixLoadIdentity(&Mat);
-}
-
-void setMatrix(rs_matrix4x4 m) {
-    Mat = m;
-}
-
-void root(const uchar4 *in, uchar4 *out) {
-    float4 f = convert_float4(*in);
-    f = rsMatrixMultiply(&Mat, f);
-    f = clamp(f, 0.f, 255.f);
-    *out = convert_uchar4(f);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve5x5.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve5x5.rs
deleted file mode 100644
index b1ad241..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve5x5.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-int32_t gWidth;
-int32_t gHeight;
-rs_allocation gIn;
-
-float gCoeffs[25];
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-    uint32_t x0 = max((int32_t)x-2, 0);
-    uint32_t x1 = max((int32_t)x-1, 0);
-    uint32_t x2 = x;
-    uint32_t x3 = min((int32_t)x+1, gWidth-1);
-    uint32_t x4 = min((int32_t)x+2, gWidth-1);
-
-    uint32_t y0 = max((int32_t)y-2, 0);
-    uint32_t y1 = max((int32_t)y-1, 0);
-    uint32_t y2 = y;
-    uint32_t y3 = min((int32_t)y+1, gHeight-1);
-    uint32_t y4 = min((int32_t)y+2, gHeight-1);
-
-    float4 p0 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y0)) * gCoeffs[0]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y0)) * gCoeffs[1]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y0)) * gCoeffs[2]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y0)) * gCoeffs[3]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y0)) * gCoeffs[4];
-
-    float4 p1 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y1)) * gCoeffs[5]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y1)) * gCoeffs[6]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y1)) * gCoeffs[7]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y1)) * gCoeffs[8]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y1)) * gCoeffs[9];
-
-    float4 p2 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y2)) * gCoeffs[10]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y2)) * gCoeffs[11]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y2)) * gCoeffs[12]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y2)) * gCoeffs[13]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y2)) * gCoeffs[14];
-
-    float4 p3 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y3)) * gCoeffs[15]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y3)) * gCoeffs[16]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y3)) * gCoeffs[17]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y3)) * gCoeffs[18]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y3)) * gCoeffs[19];
-
-    float4 p4 = convert_float4(rsGetElementAt_uchar4(gIn, x0, y4)) * gCoeffs[20]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x1, y4)) * gCoeffs[21]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x2, y4)) * gCoeffs[22]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x3, y4)) * gCoeffs[23]
-              + convert_float4(rsGetElementAt_uchar4(gIn, x4, y4)) * gCoeffs[24];
-
-    p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
-    p0.a = 255.f;
-    *out = convert_uchar4(p0);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/copy.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/copy.rs
deleted file mode 100644
index 31e4241..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/copy.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-void root(const uchar4 *v_in, uchar4 *v_out) {
-    *v_out = *v_in;
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh
deleted file mode 100644
index 3809912..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-rs_allocation in_alloc;
-rs_sampler sampler;
-
-static float2 center, neg_center, inv_dimensions, axis_scale;
-static float alpha, radius2, factor;
-
-void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) {
-    center.x = center_x;
-    center.y = center_y;
-    neg_center = -center;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-    alpha = k * 2.0 + 0.75;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-    
-    const float bound2 = 0.25 * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y);
-    const float bound = sqrt(bound2);
-    const float radius = 1.15 * bound;
-    radius2 = radius*radius;
-    const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2));
-    factor = bound / max_radian;
-}
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float2 scaledCoord = axis_scale * coord;
-    const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
-    const float inv_dist = rsqrt(dist2);
-    const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist2)) * inv_dist);
-    const float scalar = radian * factor * inv_dist;
-    const float2 new_coord = mad(coord, scalar, center);
-    const float4 fout = rsSample(in_alloc, sampler, new_coord);
-    *out = rsPackColorTo8888(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx.rsh
deleted file mode 100644
index 08b4126..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx.rsh
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-rs_allocation in_alloc;
-rs_sampler sampler;
-
-static float2 center, neg_center, inv_dimensions, axis_scale;
-static float alpha, radius2, factor;
-
-void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) {
-    center.x = center_x;
-    center.y = center_y;
-    neg_center = -center;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-    alpha = k * 2.0 + 0.75;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float bound2 = 0.25 * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y);
-    const float bound = sqrt(bound2);
-    const float radius = 1.15 * bound;
-    radius2 = radius*radius;
-    const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2));
-    factor = bound / max_radian;
-}
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float2 scaledCoord = axis_scale * coord;
-    const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
-    const float inv_dist = half_rsqrt(dist2);
-    const float radian = M_PI_2 - atan((alpha * half_sqrt(radius2 - dist2)) * inv_dist);
-    const float scalar = radian * factor * inv_dist;
-    const float2 new_coord = mad(coord, scalar, center);
-    const float4 fout = rsSample(in_alloc, sampler, new_coord);
-    *out = rsPackColorTo8888(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_full.rs
deleted file mode 100644
index cce42f9..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-#include "fisheye_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_relaxed.rs
deleted file mode 100644
index 64d27ed..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_approx_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-#include "fisheye_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_full.rs
deleted file mode 100644
index e42df13..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-#include "fisheye.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_relaxed.rs
deleted file mode 100644
index 990310b..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-#include "fisheye.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs
deleted file mode 100644
index 44320a5..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-void genRand(uchar *out) {
-    *out = (uchar)rsRand(0xff);
-}
-
-/*
- * Convolution matrix of distance 2 with fixed point of 'kShiftBits' bits
- * shifted. Thus the sum of this matrix should be 'kShiftValue'. Entries of
- * small values are not calculated to gain efficiency.
- * The order ot pixels represented in this matrix is:
- *  1  2  3
- *  4  0  5
- *  6  7  8
- *  and the matrix should be: {230, 56, 114, 56, 114, 114, 56, 114, 56}.
- *  However, since most of the valus are identical, we only use the first three
- *  entries and the entries corresponding to the pixels is:
- *  1  2  1
- *  2  0  2
- *  1  2  1
- */
-
-int32_t gWMask;
-int32_t gHMask;
-
-rs_allocation gBlendSource;
-void blend9(uchar *out, uint32_t x, uint32_t y) {
-    uint32_t x1 = (x-1) & gWMask;
-    uint32_t x2 = (x+1) & gWMask;
-    uint32_t y1 = (y-1) & gHMask;
-    uint32_t y2 = (y+1) & gHMask;
-
-    uint p00 = 56 *  rsGetElementAt_uchar(gBlendSource, x1, y1);
-    uint p01 = 114 * rsGetElementAt_uchar(gBlendSource, x, y1);
-    uint p02 = 56 *  rsGetElementAt_uchar(gBlendSource, x2, y1);
-    uint p10 = 114 * rsGetElementAt_uchar(gBlendSource, x1, y);
-    uint p11 = 230 * rsGetElementAt_uchar(gBlendSource, x, y);
-    uint p12 = 114 * rsGetElementAt_uchar(gBlendSource, x2, y);
-    uint p20 = 56 *  rsGetElementAt_uchar(gBlendSource, x1, y2);
-    uint p21 = 114 * rsGetElementAt_uchar(gBlendSource, x, y2);
-    uint p22 = 56 *  rsGetElementAt_uchar(gBlendSource, x2, y2);
-
-    p00 += p01;
-    p02 += p10;
-    p11 += p12;
-    p20 += p21;
-
-    p22 += p00;
-    p02 += p11;
-
-    p20 += p22;
-    p20 += p02;
-
-    p20 = min(p20 >> 10, (uint)255);
-    *out = (uchar)p20;
-}
-
-float gNoiseStrength;
-
-rs_allocation gNoise;
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    float4 ip = convert_float4(*in);
-    float pnoise = (float) rsGetElementAt_uchar(gNoise, x & gWMask, y & gHMask);
-
-    float energy_level = ip.r + ip.g + ip.b;
-    float energy_mask = (28.f - sqrt(energy_level)) * 0.03571f;
-    pnoise = (pnoise - 128.f) * energy_mask;
-
-    ip += pnoise * gNoiseStrength;
-    ip = clamp(ip, 0.f, 255.f);
-
-    uchar4 p = convert_uchar4(ip);
-    p.a = 0xff;
-    *out = p;
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/greyscale.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/greyscale.rs
deleted file mode 100644
index b5abf3f0..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/greyscale.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-
-void root(const uchar4 *v_in, uchar4 *v_out) {
-    float4 f4 = rsUnpackColor8888(*v_in);
-
-    float3 mono = dot(f4.rgb, gMonoMult);
-    *v_out = rsPackColorTo8888(mono);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip2_convolve3x3.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip2_convolve3x3.rs
deleted file mode 100644
index 13f9032..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip2_convolve3x3.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-int32_t gWidth;
-int32_t gHeight;
-rs_allocation gIn;
-
-float gCoeffs[9];
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-    uint32_t x1 = min((int32_t)x+1, gWidth-1);
-    uint32_t x2 = max((int32_t)x-1, 0);
-    uint32_t y1 = min((int32_t)y+1, gHeight-1);
-    uint32_t y2 = max((int32_t)y-1, 0);
-
-    float4 p00 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y1))[0]);
-    float4 p01 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y1))[0]);
-    float4 p02 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y1))[0]);
-    float4 p10 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y))[0]);
-    float4 p11 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y))[0]);
-    float4 p12 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y))[0]);
-    float4 p20 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y2))[0]);
-    float4 p21 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y2))[0]);
-    float4 p22 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y2))[0]);
-    p00 *= gCoeffs[0];
-    p01 *= gCoeffs[1];
-    p02 *= gCoeffs[2];
-    p10 *= gCoeffs[3];
-    p11 *= gCoeffs[4];
-    p12 *= gCoeffs[5];
-    p20 *= gCoeffs[6];
-    p21 *= gCoeffs[7];
-    p22 *= gCoeffs[8];
-
-    p00 += p01;
-    p02 += p10;
-    p11 += p12;
-    p20 += p21;
-
-    p22 += p00;
-    p02 += p11;
-
-    p20 += p22;
-    p20 += p02;
-
-    p20 = clamp(p20, 0.f, 255.f);
-    *out = convert_uchar4(p20);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels.rsh
deleted file mode 100644
index 7c5d930..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels.rsh
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-float inBlack;
-float outBlack;
-float inWMinInB;
-float outWMinOutB;
-float overInWMinInB;
-rs_matrix3x3 colorMat;
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    float3 pixel = convert_float4(in[0]).rgb;
-    pixel = rsMatrixMultiply(&colorMat, pixel);
-    pixel = clamp(pixel, 0.f, 255.f);
-    pixel = (pixel - inBlack) * overInWMinInB;
-    pixel = pixel * outWMinOutB + outBlack;
-    pixel = clamp(pixel, 0.f, 255.f);
-    out->xyz = convert_uchar3(pixel);
-    out->w = 0xff;
-}
-
-void root4(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    float4 pixel = convert_float4(in[0]);
-    pixel.rgb = rsMatrixMultiply(&colorMat, pixel.rgb);
-    pixel = clamp(pixel, 0.f, 255.f);
-    pixel = (pixel - inBlack) * overInWMinInB;
-    pixel = pixel * outWMinOutB + outBlack;
-    pixel = clamp(pixel, 0.f, 255.f);
-    out->xyzw = convert_uchar4(pixel);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_full.rs
deleted file mode 100644
index a4aa388..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-#include "levels.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_relaxed.rs
deleted file mode 100644
index ffdcfe3..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-#include "levels.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/mandelbrot.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/mandelbrot.rs
deleted file mode 100644
index 5b3912d..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/mandelbrot.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2011 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-uint32_t gMaxIteration = 500;
-uint32_t gDimX = 1024;
-uint32_t gDimY = 1024;
-
-float lowerBoundX = -2.f;
-float lowerBoundY = -2.f;
-float scaleFactor = 4.f;
-
-void root(uchar4 *v_out, uint32_t x, uint32_t y) {
-  float2 p;
-  p.x = lowerBoundX + ((float)x / gDimX) * scaleFactor;
-  p.y = lowerBoundY + ((float)y / gDimY) * scaleFactor;
-
-  float2 t = 0;
-  float2 t2 = t * t;
-  int iter = 0;
-  while((t2.x + t2.y < 4.f) && (iter < gMaxIteration)) {
-    float xtemp = t2.x - t2.y + p.x;
-    t.y = 2 * t.x * t.y + p.y;
-    t.x = xtemp;
-    iter++;
-    t2 = t * t;
-  }
-
-  if(iter >= gMaxIteration) {
-    // write a non-transparent black pixel
-    *v_out = (uchar4){0, 0, 0, 0xff};
-  } else {
-    float mi3 = gMaxIteration / 3.f;
-    if (iter <= (gMaxIteration / 3))
-      *v_out = (uchar4){0xff * (iter / mi3), 0, 0, 0xff};
-    else if (iter <= (((gMaxIteration / 3) * 2)))
-      *v_out = (uchar4){0xff - (0xff * ((iter - mi3) / mi3)),
-                        (0xff * ((iter - mi3) / mi3)), 0, 0xff};
-    else
-      *v_out = (uchar4){0, 0xff - (0xff * ((iter - (mi3 * 2)) / mi3)),
-                        (0xff * ((iter - (mi3 * 2)) / mi3)), 0xff};
-  }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs
deleted file mode 100644
index 9ef4898..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-
-int height;
-int width;
-static int radius;
-
-rs_allocation InPixel;
-rs_allocation ScratchPixel1;
-rs_allocation ScratchPixel2;
-
-const int MAX_RADIUS = 25;
-
-// Store our coefficients here
-static float gaussian[MAX_RADIUS * 2 + 1];
-
-void setRadius(int rad) {
-    radius = rad;
-    // Compute gaussian weights for the blur
-    // e is the euler's number
-    float e = 2.718281828459045f;
-    float pi = 3.1415926535897932f;
-    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
-    // x is of the form [-radius .. 0 .. radius]
-    // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.4  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.4f * (float)radius + 0.6f;
-
-    // Now compute the coefficints
-    // We will store some redundant values to save some math during
-    // the blur calculations
-    // precompute some values
-    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
-    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
-
-    float normalizeFactor = 0.0f;
-    float floatR = 0.0f;
-    for (int r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
-        normalizeFactor += gaussian[r + radius];
-    }
-
-    //Now we need to normalize the weights because all our coefficients need to add up to one
-    normalizeFactor = 1.0f / normalizeFactor;
-    for (int r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] *= normalizeFactor;
-    }
-}
-
-void copyIn(const uchar4 *in, float4 *out) {
-    *out = convert_float4(*in);
-}
-
-void vert(uchar4 *out, uint32_t x, uint32_t y) {
-    float3 blurredPixel = 0;
-    const float *gPtr = gaussian;
-    if ((y > radius) && (y < (height - radius))) {
-        for (int r = -radius; r <= radius; r ++) {
-            const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel2, x, y + r);
-            blurredPixel += i->xyz * gPtr[0];
-            gPtr++;
-        }
-    } else {
-        for (int r = -radius; r <= radius; r ++) {
-            int validH = rsClamp((int)y + r, (int)0, (int)(height - 1));
-            const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel2, x, validH);
-            blurredPixel += i->xyz * gPtr[0];
-            gPtr++;
-        }
-    }
-
-    out->xyz = convert_uchar3(clamp(blurredPixel, 0.f, 255.f));
-    out->w = 0xff;
-}
-
-void horz(float4 *out, uint32_t x, uint32_t y) {
-    float3 blurredPixel = 0;
-    const float *gPtr = gaussian;
-    if ((x > radius) && (x < (width - radius))) {
-        for (int r = -radius; r <= radius; r ++) {
-            const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel1, x + r, y);
-            blurredPixel += i->xyz * gPtr[0];
-            gPtr++;
-        }
-    } else {
-        for (int r = -radius; r <= radius; r ++) {
-            // Stepping left and right away from the pixel
-            int validX = rsClamp((int)x + r, (int)0, (int)(width - 1));
-            const float4 *i = (const float4 *)rsGetElementAt(ScratchPixel1, validX, y);
-            blurredPixel += i->xyz * gPtr[0];
-            gPtr++;
-        }
-    }
-
-    out->xyz = blurredPixel;
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette.rsh
deleted file mode 100644
index a1e4ae5..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette.rsh
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-static float2 neg_center, axis_scale, inv_dimensions;
-static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade;
-
-void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y,
-        float desired_scale, float desired_shade, float desired_slope) {
-
-    neg_center.x = -center_x;
-    neg_center.y = -center_y;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float max_dist = 0.5 * length(axis_scale);
-    sloped_inv_max_dist = desired_slope * 1.f/max_dist;
-
-    // Range needs to be between 1.3 to 0.6. When scale is zero then range is
-    // 1.3 which means no vignette at all because the luminousity difference is
-    // less than 1/256.  Expect input scale to be between 0.0 and 1.0.
-    const float neg_range = 0.7*sqrt(desired_scale) - 1.3;
-    sloped_neg_range = exp(neg_range * desired_slope);
-
-    shade = desired_shade;
-    opp_shade = 1.f - desired_shade;
-}
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float4 fin = convert_float4(*in);
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float sloped_dist_ratio = length(axis_scale * coord)  * sloped_inv_max_dist;
-    const float lumen = opp_shade + shade / ( 1.0 + sloped_neg_range * exp(sloped_dist_ratio) );
-    float4 fout;
-    fout.rgb = fin.rgb * lumen;
-    fout.w = fin.w;
-    *out = convert_uchar4(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx.rsh
deleted file mode 100644
index 7f7bdcf..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx.rsh
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-
-static float2 neg_center, axis_scale, inv_dimensions;
-static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade;
-
-void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y,
-        float desired_scale, float desired_shade, float desired_slope) {
-
-    neg_center.x = -center_x;
-    neg_center.y = -center_y;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float max_dist = 0.5 * length(axis_scale);
-    sloped_inv_max_dist = desired_slope * 1.f/max_dist;
-
-    // Range needs to be between 1.3 to 0.6. When scale is zero then range is
-    // 1.3 which means no vignette at all because the luminousity difference is
-    // less than 1/256.  Expect input scale to be between 0.0 and 1.0.
-    const float neg_range = 0.7*sqrt(desired_scale) - 1.3;
-    sloped_neg_range = exp(neg_range * desired_slope);
-
-    shade = desired_shade;
-    opp_shade = 1.f - desired_shade;
-}
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float4 fin = convert_float4(*in);
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float sloped_dist_ratio = fast_length(axis_scale * coord)  * sloped_inv_max_dist;
-    // TODO:  add half_exp once implemented
-    const float lumen = opp_shade + shade * half_recip(1.f + sloped_neg_range * exp(sloped_dist_ratio));
-    float4 fout;
-    fout.rgb = fin.rgb * lumen;
-    fout.w = fin.w;
-    *out = convert_uchar4(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_full.rs
deleted file mode 100644
index 3612509..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-#include "vignette_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_relaxed.rs
deleted file mode 100644
index b714e9b..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_approx_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-#include "vignette_approx.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_full.rs
deleted file mode 100644
index 5fc2dda..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-
-#include "vignette.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_relaxed.rs
deleted file mode 100644
index 430b685..0000000
--- a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.image2)
-#pragma rs_fp_relaxed
-
-#include "vignette.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/Android.mk b/tests/RenderScriptTests/ImageProcessing_jb/Android.mk
deleted file mode 100644
index 6cdd1c0..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright (C) 2009 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_PACKAGE_NAME := ImageProcessingJB
-LOCAL_SDK_VERSION := 16
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing_jb/AndroidManifest.xml
deleted file mode 100644
index b3fcfc4..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.imagejb">
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-sdk android:minSdkVersion="11" />
-    <application android:label="Image Processing JB"
-                 android:hardwareAccelerated="true">
-        <activity android:name="ImageProcessingActivityJB">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/res/drawable-nodpi/img1600x1067.jpg b/tests/RenderScriptTests/ImageProcessing_jb/res/drawable-nodpi/img1600x1067.jpg
deleted file mode 100644
index 05d3ee2..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/res/drawable-nodpi/img1600x1067.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/res/drawable-nodpi/img1600x1067b.jpg b/tests/RenderScriptTests/ImageProcessing_jb/res/drawable-nodpi/img1600x1067b.jpg
deleted file mode 100644
index aed0781..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/res/drawable-nodpi/img1600x1067b.jpg
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing_jb/res/layout/main.xml
deleted file mode 100644
index f0a2b92..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/res/layout/main.xml
+++ /dev/null
@@ -1,139 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:id="@+id/toplevel">
-    <SurfaceView
-        android:id="@+id/surface"
-        android:layout_width="1dip"
-        android:layout_height="1dip" />
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="vertical"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
-            <ImageView
-                android:id="@+id/display"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-                    <Button
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/benchmark"
-                        android:onClick="benchmark"/>
-                    <TextView
-                        android:id="@+id/benchmarkText"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/saturation"/>
-            </LinearLayout>
-            <Spinner
-                android:id="@+id/filterselection"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <Spinner
-                android:id="@+id/spinner1"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider1Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/saturation"/>
-             <SeekBar
-                android:id="@+id/slider1"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider2Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/gamma"/>
-            <SeekBar
-                android:id="@+id/slider2"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider3Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:textSize="8pt"
-                android:text="@string/out_white"/>
-            <SeekBar
-                android:id="@+id/slider3"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider4Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/slider4"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/slider5Text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/slider5"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <Button
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/benchmark_all"
-                    android:onClick="benchmark_all"/>
-            </LinearLayout>
-    </ScrollView>
-</LinearLayout>
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/res/layout/spinner_layout.xml b/tests/RenderScriptTests/ImageProcessing_jb/res/layout/spinner_layout.xml
deleted file mode 100644
index 8196bbf..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/res/layout/spinner_layout.xml
+++ /dev/null
@@ -1,23 +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"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:padding="10dp"
-    android:textSize="16sp"
-/>
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing_jb/res/values/strings.xml
deleted file mode 100644
index a7dd165..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/res/values/strings.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2008 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- General -->
-    <skip />
-    <!--slider label -->
-    <string name="blur_description">Blur Radius</string>
-    <string name="in_white">In White</string>
-    <string name="out_white">Out White</string>
-    <string name="in_black">In Black</string>
-    <string name="out_black">Out Black</string>
-    <string name="gamma">Gamma</string>
-    <string name="saturation">Saturation</string>
-    <string name="benchmark">Benchmark</string>
-    <string name="benchmark_all">Benchmark All</string>
-
-</resources>
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Blur25.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Blur25.java
deleted file mode 100644
index d7e918b..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Blur25.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Blur25 extends TestBase {
-    private int MAX_RADIUS = 25;
-    private ScriptC_threshold mScript;
-    private float mRadius = MAX_RADIUS;
-    private float mSaturation = 1.0f;
-    private Allocation mScratchPixelsAllocation1;
-    private Allocation mScratchPixelsAllocation2;
-
-
-    public Blur25() {
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Radius");
-        b.setProgress(100);
-        return true;
-    }
-
-
-    public void onBar1Changed(int progress) {
-        mRadius = ((float)progress) / 100.0f * MAX_RADIUS;
-        if (mRadius <= 0.10f) {
-            mRadius = 0.10f;
-        }
-        mScript.invoke_setRadius((int)mRadius);
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
-        tb.setX(width);
-        tb.setY(height);
-        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
-        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
-
-        mScript = new ScriptC_threshold(mRS, res, R.raw.threshold);
-        mScript.set_width(width);
-        mScript.set_height(height);
-        mScript.invoke_setRadius(MAX_RADIUS);
-
-        mScript.set_InPixel(mInPixelsAllocation);
-        mScript.set_ScratchPixel1(mScratchPixelsAllocation1);
-        mScript.set_ScratchPixel2(mScratchPixelsAllocation2);
-    }
-
-    public void runTest() {
-        mScript.forEach_copyIn(mInPixelsAllocation, mScratchPixelsAllocation1);
-        mScript.forEach_horz(mScratchPixelsAllocation2);
-        mScript.forEach_vert(mOutPixelsAllocation);
-    }
-
-    public void setupBenchmark() {
-        mScript.invoke_setRadius(MAX_RADIUS);
-    }
-
-    public void exitBenchmark() {
-        mScript.invoke_setRadius((int)mRadius);
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/ColorMatrix.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/ColorMatrix.java
deleted file mode 100644
index 62ca694..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/ColorMatrix.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class ColorMatrix extends TestBase {
-    private ScriptC_colormatrix mScript;
-    private boolean mUseGrey;
-
-    public ColorMatrix(boolean useGrey) {
-        mUseGrey = useGrey;
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        Matrix4f m = new Matrix4f();
-        m.set(1, 0, 0.2f);
-        m.set(1, 1, 0.9f);
-        m.set(1, 2, 0.2f);
-
-        mScript = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
-        mScript.invoke_setMatrix(m);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Convolve3x3.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Convolve3x3.java
deleted file mode 100644
index 6673032..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Convolve3x3.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Convolve3x3 extends TestBase {
-    private ScriptC_convolve3x3 mScript;
-
-    private int mWidth;
-    private int mHeight;
-
-    public Convolve3x3() {
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        float f[] = new float[9];
-        f[0] =  0.f;    f[1] = -1.f;    f[2] =  0.f;
-        f[3] = -1.f;    f[4] =  5.f;    f[5] = -1.f;
-        f[6] =  0.f;    f[7] = -1.f;    f[8] =  0.f;
-
-        mScript = new ScriptC_convolve3x3(mRS, res, R.raw.convolve3x3);
-        mScript.set_gCoeffs(f);
-        mScript.set_gIn(mInPixelsAllocation);
-        mScript.set_gWidth(mWidth);
-        mScript.set_gHeight(mHeight);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Convolve5x5.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Convolve5x5.java
deleted file mode 100644
index 895d459..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Convolve5x5.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix4f;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Convolve5x5 extends TestBase {
-    private ScriptC_convolve5x5 mScript;
-
-    private int mWidth;
-    private int mHeight;
-
-    public Convolve5x5() {
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mWidth = mInPixelsAllocation.getType().getX();
-        mHeight = mInPixelsAllocation.getType().getY();
-
-        float f[] = new float[25];
-        //f[0] = 0.012f; f[1] = 0.025f; f[2] = 0.031f; f[3] = 0.025f; f[4] = 0.012f;
-        //f[5] = 0.025f; f[6] = 0.057f; f[7] = 0.075f; f[8] = 0.057f; f[9] = 0.025f;
-        //f[10]= 0.031f; f[11]= 0.075f; f[12]= 0.095f; f[13]= 0.075f; f[14]= 0.031f;
-        //f[15]= 0.025f; f[16]= 0.057f; f[17]= 0.075f; f[18]= 0.057f; f[19]= 0.025f;
-        //f[20]= 0.012f; f[21]= 0.025f; f[22]= 0.031f; f[23]= 0.025f; f[24]= 0.012f;
-
-        //f[0] = 1.f; f[1] = 2.f; f[2] = 0.f; f[3] = -2.f; f[4] = -1.f;
-        //f[5] = 4.f; f[6] = 8.f; f[7] = 0.f; f[8] = -8.f; f[9] = -4.f;
-        //f[10]= 6.f; f[11]=12.f; f[12]= 0.f; f[13]=-12.f; f[14]= -6.f;
-        //f[15]= 4.f; f[16]= 8.f; f[17]= 0.f; f[18]= -8.f; f[19]= -4.f;
-        //f[20]= 1.f; f[21]= 2.f; f[22]= 0.f; f[23]= -2.f; f[24]= -1.f;
-
-        f[0] = -1.f; f[1] = -3.f; f[2] = -4.f; f[3] = -3.f; f[4] = -1.f;
-        f[5] = -3.f; f[6] =  0.f; f[7] =  6.f; f[8] =  0.f; f[9] = -3.f;
-        f[10]= -4.f; f[11]=  6.f; f[12]= 20.f; f[13]=  6.f; f[14]= -4.f;
-        f[15]= -3.f; f[16]=  0.f; f[17]=  6.f; f[18]=  0.f; f[19]= -3.f;
-        f[20]= -1.f; f[21]= -3.f; f[22]= -4.f; f[23]= -3.f; f[24]= -1.f;
-
-        mScript = new ScriptC_convolve5x5(mRS, res, R.raw.convolve5x5);
-        mScript.set_gCoeffs(f);
-        mScript.set_gIn(mInPixelsAllocation);
-        mScript.set_gWidth(mWidth);
-        mScript.set_gHeight(mHeight);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Copy.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Copy.java
deleted file mode 100644
index 1bdee4b..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Copy.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Copy extends TestBase {
-    private ScriptC_copy mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_copy(mRS, res, R.raw.copy);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Grain.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Grain.java
deleted file mode 100644
index 5cd19a2..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Grain.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Grain extends TestBase {
-    private ScriptC_grain mScript;
-    private Allocation mNoise;
-    private Allocation mNoise2;
-
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Strength");
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        float s = progress / 100.0f;
-        mScript.set_gNoiseStrength(s);
-    }
-
-    private int findHighBit(int v) {
-        int bit = 0;
-        while (v > 1) {
-            bit++;
-            v >>= 1;
-        }
-        return bit;
-    }
-
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mInPixelsAllocation.getType().getX();
-        int height = mInPixelsAllocation.getType().getY();
-
-        int noiseW = findHighBit(width);
-        int noiseH = findHighBit(height);
-        if (noiseW > 9) {
-            noiseW = 9;
-        }
-        if (noiseH > 9) {
-            noiseH = 9;
-        }
-        noiseW = 1 << noiseW;
-        noiseH = 1 << noiseH;
-
-        Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS));
-        tb.setX(noiseW);
-        tb.setY(noiseH);
-        mNoise = Allocation.createTyped(mRS, tb.create());
-        mNoise2 = Allocation.createTyped(mRS, tb.create());
-
-        mScript = new ScriptC_grain(mRS, res, R.raw.grain);
-        mScript.set_gWMask(noiseW - 1);
-        mScript.set_gHMask(noiseH - 1);
-        mScript.set_gNoiseStrength(0.5f);
-        mScript.set_gBlendSource(mNoise);
-        mScript.set_gNoise(mNoise2);
-    }
-
-    public void runTest() {
-        mScript.forEach_genRand(mNoise);
-        mScript.forEach_blend9(mNoise2);
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Greyscale.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Greyscale.java
deleted file mode 100644
index f1952e7..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Greyscale.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-
-public class Greyscale extends TestBase {
-    private ScriptC_greyscale mScript;
-
-    public void createTest(android.content.res.Resources res) {
-        mScript = new ScriptC_greyscale(mRS, res, R.raw.greyscale);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-    }
-
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/ImageProcessingActivityJB.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/ImageProcessingActivityJB.java
deleted file mode 100644
index b3b06d4..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/ImageProcessingActivityJB.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.renderscript.ScriptC;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Script;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.view.View;
-import android.util.Log;
-import java.lang.Math;
-
-import android.os.Environment;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-public class ImageProcessingActivityJB extends Activity
-                                       implements SeekBar.OnSeekBarChangeListener {
-    private final String TAG = "Img";
-    private final String RESULT_FILE = "image_processing_result.csv";
-
-    Bitmap mBitmapIn;
-    Bitmap mBitmapIn2;
-    Bitmap mBitmapOut;
-    String mTestNames[];
-
-    private Spinner mSpinner;
-    private SeekBar mBar1;
-    private SeekBar mBar2;
-    private SeekBar mBar3;
-    private SeekBar mBar4;
-    private SeekBar mBar5;
-    private TextView mText1;
-    private TextView mText2;
-    private TextView mText3;
-    private TextView mText4;
-    private TextView mText5;
-
-    private float mSaturation = 1.0f;
-
-    private TextView mBenchmarkResult;
-    private Spinner mTestSpinner;
-
-    private SurfaceView mSurfaceView;
-    private ImageView mDisplayView;
-
-    private boolean mDoingBenchmark;
-
-    private TestBase mTest;
-    private int mRunCount;
-
-    public void updateDisplay() {
-        mHandler.sendMessage(Message.obtain());
-    }
-
-    private Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            mTest.updateBitmap(mBitmapOut);
-            mDisplayView.invalidate();
-
-            android.util.Log.v("Img", "mRunCount hdl " + mRunCount);
-            boolean doTest = false;
-            synchronized(this) {
-                if (mRunCount > 0) {
-                    mRunCount--;
-                    if (mRunCount > 0) {
-                        doTest = true;
-                    }
-                }
-            }
-            if (doTest) {
-                mTest.runTestSendMessage();
-            }
-        }
-
-    };
-
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        if (fromUser) {
-
-            if (seekBar == mBar1) {
-                mTest.onBar1Changed(progress);
-            } else if (seekBar == mBar2) {
-                mTest.onBar2Changed(progress);
-            } else if (seekBar == mBar3) {
-                mTest.onBar3Changed(progress);
-            } else if (seekBar == mBar4) {
-                mTest.onBar4Changed(progress);
-            } else if (seekBar == mBar5) {
-                mTest.onBar5Changed(progress);
-            }
-
-            boolean doTest = false;
-            synchronized(this) {
-                if (mRunCount == 0) {
-                    doTest = true;
-                    mRunCount = 1;
-                } else {
-                    mRunCount = 2;
-                }
-            }
-            if (doTest) {
-                mTest.runTestSendMessage();
-            }
-        }
-    }
-
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-    }
-
-    void setupBars() {
-        mSpinner.setVisibility(View.VISIBLE);
-        mTest.onSpinner1Setup(mSpinner);
-
-        mBar1.setVisibility(View.VISIBLE);
-        mText1.setVisibility(View.VISIBLE);
-        mTest.onBar1Setup(mBar1, mText1);
-
-        mBar2.setVisibility(View.VISIBLE);
-        mText2.setVisibility(View.VISIBLE);
-        mTest.onBar2Setup(mBar2, mText2);
-
-        mBar3.setVisibility(View.VISIBLE);
-        mText3.setVisibility(View.VISIBLE);
-        mTest.onBar3Setup(mBar3, mText3);
-
-        mBar4.setVisibility(View.VISIBLE);
-        mText4.setVisibility(View.VISIBLE);
-        mTest.onBar4Setup(mBar4, mText4);
-
-        mBar5.setVisibility(View.VISIBLE);
-        mText5.setVisibility(View.VISIBLE);
-        mTest.onBar5Setup(mBar5, mText5);
-    }
-
-
-    void changeTest(int testID) {
-        if (mTest != null) {
-            mTest.destroy();
-        }
-        switch(testID) {
-        case 0:
-            mTest = new LevelsV4(false, false);
-            break;
-        case 1:
-            mTest = new LevelsV4(false, true);
-            break;
-        case 2:
-            mTest = new LevelsV4(true, false);
-            break;
-        case 3:
-            mTest = new LevelsV4(true, true);
-            break;
-        case 4:
-            mTest = new Blur25();
-            break;
-        case 5:
-            mTest = new Greyscale();
-            break;
-        case 6:
-            mTest = new Grain();
-            break;
-        case 7:
-            mTest = new Vignette(false);
-            break;
-        case 8:
-            mTest = new Vignette(true);
-            break;
-        case 9:
-            mTest = new Convolve3x3();
-            break;
-        case 10:
-            mTest = new ColorMatrix(false);
-            break;
-        case 11:
-            mTest = new Copy();
-            break;
-        case 12:
-            mTest = new Convolve5x5();
-            break;
-        case 13:
-            mTest = new Mandelbrot();
-            break;
-        }
-
-        mTest.createBaseTest(this, mBitmapIn, mBitmapIn2);
-        setupBars();
-
-        mTest.runTest();
-        updateDisplay();
-        mBenchmarkResult.setText("Result: not run");
-    }
-
-    void setupTests() {
-        mTestNames = new String[14];
-        mTestNames[0] = "Levels Vec3 Relaxed";
-        mTestNames[1] = "Levels Vec4 Relaxed";
-        mTestNames[2] = "Levels Vec3 Full";
-        mTestNames[3] = "Levels Vec4 Full";
-        mTestNames[4] = "Blur radius 25";
-        mTestNames[5] = "Greyscale";
-        mTestNames[6] = "Grain";
-        mTestNames[7] = "Vignette Full";
-        mTestNames[8] = "Vignette Relaxed";
-        mTestNames[9] = "Convolve 3x3";
-        mTestNames[10] = "ColorMatrix";
-        mTestNames[11] = "Copy";
-        mTestNames[12] = "Convolve 5x5";
-        mTestNames[13] = "Mandelbrot";
-
-        mTestSpinner.setAdapter(new ArrayAdapter<String>(
-            this, R.layout.spinner_layout, mTestNames));
-    }
-
-    private AdapterView.OnItemSelectedListener mTestSpinnerListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-                    changeTest(pos);
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-            };
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        mBitmapIn = loadBitmap(R.drawable.img1600x1067);
-        mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b);
-        mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
-                                         mBitmapIn.getConfig());
-
-        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
-
-        mDisplayView = (ImageView) findViewById(R.id.display);
-        mDisplayView.setImageBitmap(mBitmapOut);
-
-        mSpinner = (Spinner) findViewById(R.id.spinner1);
-
-        mBar1 = (SeekBar) findViewById(R.id.slider1);
-        mBar2 = (SeekBar) findViewById(R.id.slider2);
-        mBar3 = (SeekBar) findViewById(R.id.slider3);
-        mBar4 = (SeekBar) findViewById(R.id.slider4);
-        mBar5 = (SeekBar) findViewById(R.id.slider5);
-
-        mBar1.setOnSeekBarChangeListener(this);
-        mBar2.setOnSeekBarChangeListener(this);
-        mBar3.setOnSeekBarChangeListener(this);
-        mBar4.setOnSeekBarChangeListener(this);
-        mBar5.setOnSeekBarChangeListener(this);
-
-        mText1 = (TextView) findViewById(R.id.slider1Text);
-        mText2 = (TextView) findViewById(R.id.slider2Text);
-        mText3 = (TextView) findViewById(R.id.slider3Text);
-        mText4 = (TextView) findViewById(R.id.slider4Text);
-        mText5 = (TextView) findViewById(R.id.slider5Text);
-
-        mTestSpinner = (Spinner) findViewById(R.id.filterselection);
-        mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
-
-        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
-        mBenchmarkResult.setText("Result: not run");
-
-        setupTests();
-        changeTest(0);
-    }
-
-
-    private Bitmap loadBitmap(int resource) {
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        return BitmapFactory.decodeResource(getResources(), resource, options);
-    }
-
-    // button hook
-    public void benchmark(View v) {
-        float t = getBenchmark();
-        //long javaTime = javaFilter();
-        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
-        mBenchmarkResult.setText("Result: " + t + " ms");
-        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
-    }
-
-    public void benchmark_all(View v) {
-        // write result into a file
-        File externalStorage = Environment.getExternalStorageDirectory();
-        if (!externalStorage.canWrite()) {
-            Log.v(TAG, "sdcard is not writable");
-            return;
-        }
-        File resultFile = new File(externalStorage, RESULT_FILE);
-        resultFile.setWritable(true, false);
-        try {
-            BufferedWriter rsWriter = new BufferedWriter(new FileWriter(resultFile));
-            Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath());
-            for (int i = 0; i < mTestNames.length; i++ ) {
-                changeTest(i);
-                float t = getBenchmark();
-                String s = new String("" + mTestNames[i] + ", " + t);
-                rsWriter.write(s + "\n");
-                Log.v(TAG, "Test " + s + "ms\n");
-            }
-            rsWriter.close();
-        } catch (IOException e) {
-            Log.v(TAG, "Unable to write result file " + e.getMessage());
-        }
-        changeTest(0);
-    }
-
-    // For benchmark test
-    public float getBenchmark() {
-        mDoingBenchmark = true;
-
-        mTest.setupBenchmark();
-        long result = 0;
-
-        //Log.v(TAG, "Warming");
-        long t = java.lang.System.currentTimeMillis() + 250;
-        do {
-            mTest.runTest();
-            mTest.finish();
-        } while (t > java.lang.System.currentTimeMillis());
-
-
-        //Log.v(TAG, "Benchmarking");
-        int ct = 0;
-        t = java.lang.System.currentTimeMillis();
-        do {
-            mTest.runTest();
-            mTest.finish();
-            ct++;
-        } while ((t+1000) > java.lang.System.currentTimeMillis());
-        t = java.lang.System.currentTimeMillis() - t;
-        float ft = (float)t;
-        ft /= ct;
-
-        mTest.exitBenchmark();
-        mDoingBenchmark = false;
-
-        return ft;
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/LevelsV4.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/LevelsV4.java
deleted file mode 100644
index 741e480..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/LevelsV4.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Matrix3f;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-
-public class LevelsV4 extends TestBase {
-    private ScriptC_levels_relaxed mScriptR;
-    private ScriptC_levels_full mScriptF;
-    private float mInBlack = 0.0f;
-    private float mOutBlack = 0.0f;
-    private float mInWhite = 255.0f;
-    private float mOutWhite = 255.0f;
-    private float mSaturation = 1.0f;
-
-    Matrix3f satMatrix = new Matrix3f();
-    float mInWMinInB;
-    float mOutWMinOutB;
-    float mOverInWMinInB;
-
-    boolean mUseFull;
-    boolean mUseV4;
-
-    LevelsV4(boolean useFull, boolean useV4) {
-        mUseFull = useFull;
-        mUseV4 = useV4;
-    }
-
-
-    private void setLevels() {
-        mInWMinInB = mInWhite - mInBlack;
-        mOutWMinOutB = mOutWhite - mOutBlack;
-        mOverInWMinInB = 1.f / mInWMinInB;
-
-        mScriptR.set_inBlack(mInBlack);
-        mScriptR.set_outBlack(mOutBlack);
-        mScriptR.set_inWMinInB(mInWMinInB);
-        mScriptR.set_outWMinOutB(mOutWMinOutB);
-        mScriptR.set_overInWMinInB(mOverInWMinInB);
-        mScriptF.set_inBlack(mInBlack);
-        mScriptF.set_outBlack(mOutBlack);
-        mScriptF.set_inWMinInB(mInWMinInB);
-        mScriptF.set_outWMinOutB(mOutWMinOutB);
-        mScriptF.set_overInWMinInB(mOverInWMinInB);
-    }
-
-    private void setSaturation() {
-        float rWeight = 0.299f;
-        float gWeight = 0.587f;
-        float bWeight = 0.114f;
-        float oneMinusS = 1.0f - mSaturation;
-
-        satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
-        satMatrix.set(0, 1, oneMinusS * rWeight);
-        satMatrix.set(0, 2, oneMinusS * rWeight);
-        satMatrix.set(1, 0, oneMinusS * gWeight);
-        satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
-        satMatrix.set(1, 2, oneMinusS * gWeight);
-        satMatrix.set(2, 0, oneMinusS * bWeight);
-        satMatrix.set(2, 1, oneMinusS * bWeight);
-        satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
-        mScriptR.set_colorMat(satMatrix);
-        mScriptF.set_colorMat(satMatrix);
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        b.setProgress(50);
-        t.setText("Saturation");
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(0);
-        t.setText("In Black");
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(0);
-        t.setText("Out Black");
-        return true;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(128);
-        t.setText("Out White");
-        return true;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        b.setMax(128);
-        b.setProgress(128);
-        t.setText("Out White");
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        mSaturation = (float)progress / 50.0f;
-        setSaturation();
-    }
-    public void onBar2Changed(int progress) {
-        mInBlack = (float)progress;
-        setLevels();
-    }
-    public void onBar3Changed(int progress) {
-        mOutBlack = (float)progress;
-        setLevels();
-    }
-    public void onBar4Changed(int progress) {
-        mInWhite = (float)progress + 127.0f;
-        setLevels();
-    }
-    public void onBar5Changed(int progress) {
-        mOutWhite = (float)progress + 127.0f;
-        setLevels();
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        mScriptR = new ScriptC_levels_relaxed(mRS, res, R.raw.levels_relaxed);
-        mScriptF = new ScriptC_levels_full(mRS, res, R.raw.levels_full);
-        setSaturation();
-        setLevels();
-    }
-
-    public void runTest() {
-        if (mUseFull) {
-            if (mUseV4) {
-                mScriptF.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
-            } else {
-                mScriptF.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-            }
-        } else {
-            if (mUseV4) {
-                mScriptR.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
-            } else {
-                mScriptR.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
-            }
-        }
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Mandelbrot.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Mandelbrot.java
deleted file mode 100644
index ca34848..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Mandelbrot.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import java.lang.Math;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-import android.renderscript.Script;
-import android.renderscript.ScriptC;
-import android.renderscript.Type;
-import android.util.Log;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Mandelbrot extends TestBase {
-    private ScriptC_mandelbrot mScript;
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Iterations");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        int iters = progress * 3 + 50;
-        mScript.set_gMaxIteration(iters);
-    }
-
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Lower Bound: X");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar2Changed(int progress) {
-        float scaleFactor = mScript.get_scaleFactor();
-        // allow viewport to be moved by 2x scale factor
-        float lowerBoundX = -2.f + ((progress / scaleFactor) / 50.f);
-        mScript.set_lowerBoundX(lowerBoundX);
-    }
-
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Lower Bound: Y");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar3Changed(int progress) {
-        float scaleFactor = mScript.get_scaleFactor();
-        // allow viewport to be moved by 2x scale factor
-        float lowerBoundY = -2.f + ((progress / scaleFactor) / 50.f);
-        mScript.set_lowerBoundY(lowerBoundY);
-    }
-
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        t.setText("Scale Factor");
-        b.setProgress(0);
-        return true;
-    }
-
-    public void onBar4Changed(int progress) {
-        float scaleFactor = 4.f - (3.96f * (progress / 100.f));
-        mScript.set_scaleFactor(scaleFactor);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        int width = mOutPixelsAllocation.getType().getX();
-        int height = mOutPixelsAllocation.getType().getY();
-
-        mScript = new ScriptC_mandelbrot(mRS, res, R.raw.mandelbrot);
-        mScript.set_gDimX(width);
-        mScript.set_gDimY(height);
-        mScript.set_gMaxIteration(50);
-    }
-
-    public void runTest() {
-        mScript.forEach_root(mOutPixelsAllocation);
-        mRS.finish();
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/TestBase.java
deleted file mode 100644
index ed22578..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/TestBase.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.renderscript.ScriptC;
-import android.renderscript.RenderScript;
-import android.renderscript.Type;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Script;
-import android.view.SurfaceView;
-import android.view.SurfaceHolder;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.view.View;
-import android.util.Log;
-import java.lang.Math;
-import android.widget.Spinner;
-
-public class TestBase  {
-    protected final String TAG = "Img";
-
-    protected RenderScript mRS;
-    protected Allocation mInPixelsAllocation;
-    protected Allocation mInPixelsAllocation2;
-    protected Allocation mOutPixelsAllocation;
-    protected ScriptC_msg mMessageScript;
-
-    protected ImageProcessingActivityJB act;
-
-    private class MessageProcessor extends RenderScript.RSMessageHandler {
-        ImageProcessingActivityJB mAct;
-
-        MessageProcessor(ImageProcessingActivityJB act) {
-            mAct = act;
-        }
-
-        public void run() {
-            mAct.updateDisplay();
-        }
-    }
-
-    // Override to use UI elements
-    public void onBar1Changed(int progress) {
-    }
-    public void onBar2Changed(int progress) {
-    }
-    public void onBar3Changed(int progress) {
-    }
-    public void onBar4Changed(int progress) {
-    }
-    public void onBar5Changed(int progress) {
-    }
-
-    // Override to use UI elements
-    // Unused bars will be hidden.
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        b.setVisibility(View.INVISIBLE);
-        t.setVisibility(View.INVISIBLE);
-        return false;
-    }
-
-    public boolean onSpinner1Setup(Spinner s) {
-        s.setVisibility(View.INVISIBLE);
-        return false;
-    }
-
-    public final void createBaseTest(ImageProcessingActivityJB ipact, Bitmap b, Bitmap b2) {
-        act = ipact;
-        mRS = RenderScript.create(act);
-        mRS.setMessageHandler(new MessageProcessor(act));
-        mMessageScript = new ScriptC_msg(mRS);
-        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-        mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b,
-                                                           Allocation.MipmapControl.MIPMAP_NONE,
-                                                           Allocation.USAGE_SCRIPT);
-        createTest(act.getResources());
-    }
-
-    // Must override
-    public void createTest(android.content.res.Resources res) {
-        android.util.Log.e("img", "implement createTest");
-    }
-
-    // Must override
-    public void runTest() {
-    }
-
-    final public void runTestSendMessage() {
-        android.util.Log.v("Img", "run");
-        runTest();
-        mMessageScript.invoke_sendMsg();
-    }
-
-    public void finish() {
-        mRS.finish();
-    }
-
-    public void destroy() {
-        mRS.destroy();
-        mRS = null;
-    }
-
-    public void updateBitmap(Bitmap b) {
-        mOutPixelsAllocation.copyTo(b);
-    }
-
-    // Override to configure specific benchmark config.
-    public void setupBenchmark() {
-    }
-
-    // Override to reset after benchmark.
-    public void exitBenchmark() {
-    }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Vignette.java b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Vignette.java
deleted file mode 100644
index 487cd63..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/Vignette.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.imagejb;
-
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Sampler;
-import android.renderscript.Type;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class Vignette extends TestBase {
-    private ScriptC_vignette_full mScript_full = null;
-    private ScriptC_vignette_relaxed mScript_relaxed = null;
-    private final boolean relaxed;
-    private float center_x = 0.5f;
-    private float center_y = 0.5f;
-    private float scale = 0.5f;
-    private float shade = 0.5f;
-    private float slope = 20.0f;
-
-    public Vignette(boolean relaxed) {
-        this.relaxed = relaxed;
-    }
-
-    public boolean onBar1Setup(SeekBar b, TextView t) {
-        t.setText("Scale");
-        b.setMax(100);
-        b.setProgress(25);
-        return true;
-    }
-    public boolean onBar2Setup(SeekBar b, TextView t) {
-        t.setText("Shade");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar3Setup(SeekBar b, TextView t) {
-        t.setText("Slope");
-        b.setMax(100);
-        b.setProgress(20);
-        return true;
-    }
-    public boolean onBar4Setup(SeekBar b, TextView t) {
-        t.setText("Shift center X");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-    public boolean onBar5Setup(SeekBar b, TextView t) {
-        t.setText("Shift center Y");
-        b.setMax(100);
-        b.setProgress(50);
-        return true;
-    }
-
-    public void onBar1Changed(int progress) {
-        scale = progress / 50.0f;
-        do_init();
-    }
-    public void onBar2Changed(int progress) {
-        shade = progress / 100.0f;
-        do_init();
-    }
-    public void onBar3Changed(int progress) {
-        slope = (float)progress;
-        do_init();
-    }
-    public void onBar4Changed(int progress) {
-        center_x = progress / 100.0f;
-        do_init();
-    }
-    public void onBar5Changed(int progress) {
-        center_y = progress / 100.0f;
-        do_init();
-    }
-
-    private void do_init() {
-        if (relaxed)
-            mScript_relaxed.invoke_init_vignette(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale, shade, slope);
-        else
-            mScript_full.invoke_init_vignette(
-                    mInPixelsAllocation.getType().getX(),
-                    mInPixelsAllocation.getType().getY(), center_x, center_y,
-                    scale, shade, slope);
-    }
-
-    public void createTest(android.content.res.Resources res) {
-        if (relaxed)
-            mScript_relaxed = new ScriptC_vignette_relaxed(mRS, res,
-                    R.raw.vignette_relaxed);
-        else
-            mScript_full = new ScriptC_vignette_full(mRS, res,
-                    R.raw.vignette_full);
-        do_init();
-    }
-
-    public void runTest() {
-        if (relaxed)
-            mScript_relaxed.forEach_root(mInPixelsAllocation,
-                    mOutPixelsAllocation);
-        else
-            mScript_full.forEach_root(mInPixelsAllocation,
-                    mOutPixelsAllocation);
-    }
-
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/colormatrix.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/colormatrix.rs
deleted file mode 100644
index 772cb83..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/colormatrix.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-
-static rs_matrix4x4 Mat;
-
-void init() {
-    rsMatrixLoadIdentity(&Mat);
-}
-
-void setMatrix(rs_matrix4x4 m) {
-    Mat = m;
-}
-
-void root(const uchar4 *in, uchar4 *out) {
-    float4 f = convert_float4(*in);
-    f = rsMatrixMultiply(&Mat, f);
-    f = clamp(f, 0.f, 255.f);
-    *out = convert_uchar4(f);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/convolve3x3.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/convolve3x3.rs
deleted file mode 100644
index f12f6ce..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/convolve3x3.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-int32_t gWidth;
-int32_t gHeight;
-rs_allocation gIn;
-
-float gCoeffs[9];
-
-static inline uchar4 GetElementAt_uchar4(rs_allocation a, uint32_t x, uint32_t y) {
-    return ((uchar4 *)rsGetElementAt(a, x, y))[0];
-}
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-    uint32_t x1 = min((int32_t)x+1, gWidth-1);
-    uint32_t x2 = max((int32_t)x-1, 0);
-    uint32_t y1 = min((int32_t)y+1, gHeight-1);
-    uint32_t y2 = max((int32_t)y-1, 0);
-
-    float4 p00 = convert_float4(GetElementAt_uchar4(gIn, x1, y1));
-    float4 p01 = convert_float4(GetElementAt_uchar4(gIn, x, y1));
-    float4 p02 = convert_float4(GetElementAt_uchar4(gIn, x2, y1));
-    float4 p10 = convert_float4(GetElementAt_uchar4(gIn, x1, y));
-    float4 p11 = convert_float4(GetElementAt_uchar4(gIn, x, y));
-    float4 p12 = convert_float4(GetElementAt_uchar4(gIn, x2, y));
-    float4 p20 = convert_float4(GetElementAt_uchar4(gIn, x1, y2));
-    float4 p21 = convert_float4(GetElementAt_uchar4(gIn, x, y2));
-    float4 p22 = convert_float4(GetElementAt_uchar4(gIn, x2, y2));
-    p00 *= gCoeffs[0];
-    p01 *= gCoeffs[1];
-    p02 *= gCoeffs[2];
-    p10 *= gCoeffs[3];
-    p11 *= gCoeffs[4];
-    p12 *= gCoeffs[5];
-    p20 *= gCoeffs[6];
-    p21 *= gCoeffs[7];
-    p22 *= gCoeffs[8];
-
-    p00 += p01;
-    p02 += p10;
-    p11 += p12;
-    p20 += p21;
-
-    p22 += p00;
-    p02 += p11;
-
-    p20 += p22;
-    p20 += p02;
-
-    p20 = clamp(p20, 0.f, 255.f);
-    *out = convert_uchar4(p20);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/convolve5x5.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/convolve5x5.rs
deleted file mode 100644
index 6e23d79..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/convolve5x5.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-int32_t gWidth;
-int32_t gHeight;
-rs_allocation gIn;
-
-float gCoeffs[25];
-
-static inline uchar4 GetElementAt_uchar4(rs_allocation a, uint32_t x, uint32_t y) {
-    return ((uchar4 *)rsGetElementAt(a, x, y))[0];
-}
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-    uint32_t x0 = max((int32_t)x-2, 0);
-    uint32_t x1 = max((int32_t)x-1, 0);
-    uint32_t x2 = x;
-    uint32_t x3 = min((int32_t)x+1, gWidth-1);
-    uint32_t x4 = min((int32_t)x+2, gWidth-1);
-
-    uint32_t y0 = max((int32_t)y-2, 0);
-    uint32_t y1 = max((int32_t)y-1, 0);
-    uint32_t y2 = y;
-    uint32_t y3 = min((int32_t)y+1, gHeight-1);
-    uint32_t y4 = min((int32_t)y+2, gHeight-1);
-
-    float4 p0 = convert_float4(GetElementAt_uchar4(gIn, x0, y0)) * gCoeffs[0]
-              + convert_float4(GetElementAt_uchar4(gIn, x1, y0)) * gCoeffs[1]
-              + convert_float4(GetElementAt_uchar4(gIn, x2, y0)) * gCoeffs[2]
-              + convert_float4(GetElementAt_uchar4(gIn, x3, y0)) * gCoeffs[3]
-              + convert_float4(GetElementAt_uchar4(gIn, x4, y0)) * gCoeffs[4];
-
-    float4 p1 = convert_float4(GetElementAt_uchar4(gIn, x0, y1)) * gCoeffs[5]
-              + convert_float4(GetElementAt_uchar4(gIn, x1, y1)) * gCoeffs[6]
-              + convert_float4(GetElementAt_uchar4(gIn, x2, y1)) * gCoeffs[7]
-              + convert_float4(GetElementAt_uchar4(gIn, x3, y1)) * gCoeffs[8]
-              + convert_float4(GetElementAt_uchar4(gIn, x4, y1)) * gCoeffs[9];
-
-    float4 p2 = convert_float4(GetElementAt_uchar4(gIn, x0, y2)) * gCoeffs[10]
-              + convert_float4(GetElementAt_uchar4(gIn, x1, y2)) * gCoeffs[11]
-              + convert_float4(GetElementAt_uchar4(gIn, x2, y2)) * gCoeffs[12]
-              + convert_float4(GetElementAt_uchar4(gIn, x3, y2)) * gCoeffs[13]
-              + convert_float4(GetElementAt_uchar4(gIn, x4, y2)) * gCoeffs[14];
-
-    float4 p3 = convert_float4(GetElementAt_uchar4(gIn, x0, y3)) * gCoeffs[15]
-              + convert_float4(GetElementAt_uchar4(gIn, x1, y3)) * gCoeffs[16]
-              + convert_float4(GetElementAt_uchar4(gIn, x2, y3)) * gCoeffs[17]
-              + convert_float4(GetElementAt_uchar4(gIn, x3, y3)) * gCoeffs[18]
-              + convert_float4(GetElementAt_uchar4(gIn, x4, y3)) * gCoeffs[19];
-
-    float4 p4 = convert_float4(GetElementAt_uchar4(gIn, x0, y4)) * gCoeffs[20]
-              + convert_float4(GetElementAt_uchar4(gIn, x1, y4)) * gCoeffs[21]
-              + convert_float4(GetElementAt_uchar4(gIn, x2, y4)) * gCoeffs[22]
-              + convert_float4(GetElementAt_uchar4(gIn, x3, y4)) * gCoeffs[23]
-              + convert_float4(GetElementAt_uchar4(gIn, x4, y4)) * gCoeffs[24];
-
-    p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
-    *out = convert_uchar4(p0);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/copy.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/copy.rs
deleted file mode 100644
index 17f7cff..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/copy.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-
-void root(const uchar4 *in, uchar4 *out) {
-    *out = *in;
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/grain.rs
deleted file mode 100644
index 885ef49..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/grain.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-void genRand(uchar *out) {
-    *out = (uchar)rsRand(0xff);
-}
-
-static inline uchar GetElementAt_uchar(rs_allocation a, uint32_t x, uint32_t y) {
-    return ((uchar *)rsGetElementAt(a, x, y))[0];
-}
-
-static inline float4 GetElementAt_float4(rs_allocation a, uint32_t x, uint32_t y) {
-    return ((float4 *)rsGetElementAt(a, x, y))[0];
-}
-
-/*
- * Convolution matrix of distance 2 with fixed point of 'kShiftBits' bits
- * shifted. Thus the sum of this matrix should be 'kShiftValue'. Entries of
- * small values are not calculated to gain efficiency.
- * The order ot pixels represented in this matrix is:
- *  1  2  3
- *  4  0  5
- *  6  7  8
- *  and the matrix should be: {230, 56, 114, 56, 114, 114, 56, 114, 56}.
- *  However, since most of the valus are identical, we only use the first three
- *  entries and the entries corresponding to the pixels is:
- *  1  2  1
- *  2  0  2
- *  1  2  1
- */
-
-int32_t gWMask;
-int32_t gHMask;
-
-rs_allocation gBlendSource;
-void blend9(uchar *out, uint32_t x, uint32_t y) {
-    uint32_t x1 = (x-1) & gWMask;
-    uint32_t x2 = (x+1) & gWMask;
-    uint32_t y1 = (y-1) & gHMask;
-    uint32_t y2 = (y+1) & gHMask;
-
-    uint p00 = 56 *  GetElementAt_uchar(gBlendSource, x1, y1);
-    uint p01 = 114 * GetElementAt_uchar(gBlendSource, x, y1);
-    uint p02 = 56 *  GetElementAt_uchar(gBlendSource, x2, y1);
-    uint p10 = 114 * GetElementAt_uchar(gBlendSource, x1, y);
-    uint p11 = 230 * GetElementAt_uchar(gBlendSource, x, y);
-    uint p12 = 114 * GetElementAt_uchar(gBlendSource, x2, y);
-    uint p20 = 56 *  GetElementAt_uchar(gBlendSource, x1, y2);
-    uint p21 = 114 * GetElementAt_uchar(gBlendSource, x, y2);
-    uint p22 = 56 *  GetElementAt_uchar(gBlendSource, x2, y2);
-
-    p00 += p01;
-    p02 += p10;
-    p11 += p12;
-    p20 += p21;
-
-    p22 += p00;
-    p02 += p11;
-
-    p20 += p22;
-    p20 += p02;
-
-    p20 = min(p20 >> 10, (uint)255);
-    *out = (uchar)p20;
-}
-
-float gNoiseStrength;
-
-rs_allocation gNoise;
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    float4 ip = convert_float4(*in);
-    float pnoise = (float) GetElementAt_uchar(gNoise, x & gWMask, y & gHMask);
-
-    float energy_level = ip.r + ip.g + ip.b;
-    float energy_mask = (28.f - sqrt(energy_level)) * 0.03571f;
-    pnoise = (pnoise - 128.f) * energy_mask;
-
-    ip += pnoise * gNoiseStrength;
-    ip = clamp(ip, 0.f, 255.f);
-
-    uchar4 p = convert_uchar4(ip);
-    p.a = 0xff;
-    *out = p;
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/greyscale.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/greyscale.rs
deleted file mode 100644
index b3a7ef0..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/greyscale.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-
-void root(const uchar4 *v_in, uchar4 *out) {
-    float4 f4 = rsUnpackColor8888(*v_in);
-
-    float3 mono = dot(f4.rgb, gMonoMult);
-    *out = rsPackColorTo8888(mono);
-}
-
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels.rsh b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels.rsh
deleted file mode 100644
index a3a2775..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels.rsh
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-float inBlack;
-float outBlack;
-float inWMinInB;
-float outWMinOutB;
-float overInWMinInB;
-rs_matrix3x3 colorMat;
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    float3 pixel = convert_float4(*in).rgb;
-    pixel = rsMatrixMultiply(&colorMat, pixel);
-    pixel = clamp(pixel, 0.f, 255.f);
-    pixel = (pixel - inBlack) * overInWMinInB;
-    pixel = pixel * outWMinOutB + outBlack;
-    pixel = clamp(pixel, 0.f, 255.f);
-    out->xyz = convert_uchar3(pixel);
-    out->w = 0xff;
-}
-
-void root4(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    float4 pixel = convert_float4(*in);
-    pixel.rgb = rsMatrixMultiply(&colorMat, pixel.rgb);
-    pixel = clamp(pixel, 0.f, 255.f);
-    pixel = (pixel - inBlack) * overInWMinInB;
-    pixel = pixel * outWMinOutB + outBlack;
-    pixel = clamp(pixel, 0.f, 255.f);
-    *out = convert_uchar4(pixel);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels_full.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels_full.rs
deleted file mode 100644
index dead169..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-
-#include "levels.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels_relaxed.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels_relaxed.rs
deleted file mode 100644
index b2564ef..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/levels_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-#include "levels.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/mandelbrot.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/mandelbrot.rs
deleted file mode 100644
index 7cd8488..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/mandelbrot.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (C) 2011 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-
-uint32_t gMaxIteration = 500;
-uint32_t gDimX = 1024;
-uint32_t gDimY = 1024;
-
-float lowerBoundX = -2.f;
-float lowerBoundY = -2.f;
-float scaleFactor = 4.f;
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-  float2 p;
-  p.x = lowerBoundX + ((float)x / gDimX) * scaleFactor;
-  p.y = lowerBoundY + ((float)y / gDimY) * scaleFactor;
-
-  float2 t = 0;
-  float2 t2 = t * t;
-  int iter = 0;
-  while((t2.x + t2.y < 4.f) && (iter < gMaxIteration)) {
-    float xtemp = t2.x - t2.y + p.x;
-    t.y = 2 * t.x * t.y + p.y;
-    t.x = xtemp;
-    iter++;
-    t2 = t * t;
-  }
-
-  if(iter >= gMaxIteration) {
-    // write a non-transparent black pixel
-    *out = (uchar4){0, 0, 0, 0xff};
-  } else {
-    float mi3 = gMaxIteration / 3.f;
-    if (iter <= (gMaxIteration / 3))
-      *out = (uchar4){0xff * (iter / mi3), 0, 0, 0xff};
-    else if (iter <= (((gMaxIteration / 3) * 2)))
-      *out = (uchar4){0xff - (0xff * ((iter - mi3) / mi3)),
-                      (0xff * ((iter - mi3) / mi3)), 0, 0xff};
-    else
-      *out = (uchar4){0, 0xff - (0xff * ((iter - (mi3 * 2)) / mi3)),
-                      (0xff * ((iter - (mi3 * 2)) / mi3)), 0xff};
-  }
-}
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/msg.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/msg.rs
deleted file mode 100644
index 645eb98..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/msg.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-
-void sendMsg() {
-    rsSendToClientBlocking(0);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/threshold.rs
deleted file mode 100644
index d18117a..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/threshold.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-
-int height;
-int width;
-static int radius;
-
-rs_allocation InPixel;
-rs_allocation ScratchPixel1;
-rs_allocation ScratchPixel2;
-
-const int MAX_RADIUS = 25;
-
-// Store our coefficients here
-static float gaussian[MAX_RADIUS * 2 + 1];
-
-void setRadius(int rad) {
-    radius = rad;
-    // Compute gaussian weights for the blur
-    // e is the euler's number
-    float e = 2.718281828459045f;
-    float pi = 3.1415926535897932f;
-    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
-    // x is of the form [-radius .. 0 .. radius]
-    // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.4  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.4f * (float)radius + 0.6f;
-
-    // Now compute the coefficints
-    // We will store some redundant values to save some math during
-    // the blur calculations
-    // precompute some values
-    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
-    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
-
-    float normalizeFactor = 0.0f;
-    float floatR = 0.0f;
-    for (int r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
-        normalizeFactor += gaussian[r + radius];
-    }
-
-    //Now we need to normalize the weights because all our coefficients need to add up to one
-    normalizeFactor = 1.0f / normalizeFactor;
-    for (int r = -radius; r <= radius; r ++) {
-        floatR = (float)r;
-        gaussian[r + radius] *= normalizeFactor;
-    }
-}
-
-void copyIn(const uchar4 *in, float4 *out) {
-    *out = convert_float4(*in);
-}
-
-static inline float4 GetElementAt_float4(rs_allocation a, uint32_t x, uint32_t y) {
-    return ((float4 *)rsGetElementAt(a, x, y))[0];
-}
-
-void vert(uchar4 *out, uint32_t x, uint32_t y) {
-    float3 blurredPixel = 0;
-    int gi = 0;
-    if ((y > radius) && (y < (height - radius))) {
-        for (int r = -radius; r <= radius; r ++) {
-            float4 i = GetElementAt_float4(ScratchPixel2, x, y + r);
-            blurredPixel += i.xyz * gaussian[gi++];
-        }
-    } else {
-        for (int r = -radius; r <= radius; r ++) {
-            int validH = rsClamp((int)y + r, (int)0, (int)(height - 1));
-            float4 i = GetElementAt_float4(ScratchPixel2, x, validH);
-            blurredPixel += i.xyz * gaussian[gi++];
-        }
-    }
-
-    out->xyz = convert_uchar3(clamp(blurredPixel, 0.f, 255.f));
-    out->w = 0xff;
-}
-
-void horz(float4 *out, uint32_t x, uint32_t y) {
-    float4 blurredPixel = 0;
-    int gi = 0;
-    if ((x > radius) && (x < (width - radius))) {
-        for (int r = -radius; r <= radius; r ++) {
-            float4 i = GetElementAt_float4(ScratchPixel1, x + r, y);
-            blurredPixel += i * gaussian[gi++];
-        }
-    } else {
-        for (int r = -radius; r <= radius; r ++) {
-            // Stepping left and right away from the pixel
-            int validX = rsClamp((int)x + r, (int)0, (int)(width - 1));
-            float4 i = GetElementAt_float4(ScratchPixel1, validX, y);
-            blurredPixel += i * gaussian[gi++];
-        }
-    }
-
-    *out = blurredPixel;
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette.rsh b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette.rsh
deleted file mode 100644
index 3fef0c3..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette.rsh
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-
-static float2 neg_center, axis_scale, inv_dimensions;
-static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade;
-
-void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y,
-        float desired_scale, float desired_shade, float desired_slope) {
-
-    neg_center.x = -center_x;
-    neg_center.y = -center_y;
-    inv_dimensions.x = 1.f / (float)dim_x;
-    inv_dimensions.y = 1.f / (float)dim_y;
-
-    axis_scale = (float2)1.f;
-    if (dim_x > dim_y)
-        axis_scale.y = (float)dim_y / (float)dim_x;
-    else
-        axis_scale.x = (float)dim_x / (float)dim_y;
-
-    const float max_dist = 0.5f * length(axis_scale);
-    sloped_inv_max_dist = desired_slope * 1.f/max_dist;
-
-    // Range needs to be between 1.3 to 0.6. When scale is zero then range is
-    // 1.3 which means no vignette at all because the luminousity difference is
-    // less than 1/256.  Expect input scale to be between 0.0 and 1.0.
-    const float neg_range = 0.7f*sqrt(desired_scale) - 1.3f;
-    sloped_neg_range = exp(neg_range * desired_slope);
-
-    shade = desired_shade;
-    opp_shade = 1.f - desired_shade;
-}
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    // Convert x and y to floating point coordinates with center as origin
-    const float4 fin = convert_float4(*in);
-    const float2 inCoord = {(float)x, (float)y};
-    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
-    const float sloped_dist_ratio = length(axis_scale * coord)  * sloped_inv_max_dist;
-    const float lumen = opp_shade + shade / ( 1.0f + sloped_neg_range * exp(sloped_dist_ratio) );
-    float4 fout;
-    fout.rgb = fin.rgb * lumen;
-    fout.w = fin.w;
-    *out = convert_uchar4(fout);
-}
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette_full.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette_full.rs
deleted file mode 100644
index c5b08a9..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette_full.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-
-#include "vignette.rsh"
-
diff --git a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette_relaxed.rs b/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette_relaxed.rs
deleted file mode 100644
index 339b747..0000000
--- a/tests/RenderScriptTests/ImageProcessing_jb/src/com/android/rs/image/vignette_relaxed.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.imagejb)
-#pragma rs_fp_relaxed
-
-#include "vignette.rsh"
-
diff --git a/tests/RenderScriptTests/LatencyBenchmark/Android.mk b/tests/RenderScriptTests/LatencyBenchmark/Android.mk
deleted file mode 100644
index ef2164d..0000000
--- a/tests/RenderScriptTests/LatencyBenchmark/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsLatencyBenchmark
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/LatencyBenchmark/AndroidManifest.xml b/tests/RenderScriptTests/LatencyBenchmark/AndroidManifest.xml
deleted file mode 100644
index 923bb88..0000000
--- a/tests/RenderScriptTests/LatencyBenchmark/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.latencybench">
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-sdk android:minSdkVersion="17" />
-    <application android:label="_RS_Latency_Bench">
-        <activity android:name="LatencyBench">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/LatencyBenchmark/res/layout/main.xml b/tests/RenderScriptTests/LatencyBenchmark/res/layout/main.xml
deleted file mode 100644
index 9e9dab8..0000000
--- a/tests/RenderScriptTests/LatencyBenchmark/res/layout/main.xml
+++ /dev/null
@@ -1,31 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-    <ImageView
-        android:id="@+id/displayin"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-    <ImageView
-        android:id="@+id/displayout"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-</LinearLayout>
diff --git a/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/Benchmark.java b/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/Benchmark.java
deleted file mode 100644
index ee14fb9..0000000
--- a/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/Benchmark.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.latencybench;
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class Benchmark implements Runnable {
-    private final RenderScript mRS;
-    private ScriptC_compute_benchmark mScript;
-    private Allocation ain;
-    private Allocation aout;
-
-    public Benchmark(RenderScript rs, Resources res) {
-        mRS = rs;
-        mScript = new ScriptC_compute_benchmark(mRS, res, R.raw.compute_benchmark);
-        ain = Allocation.createSized(rs, Element.U32(mRS), 10000);
-        aout = Allocation.createSized(rs, Element.U32(mRS), 10000);
-    }
-
-    public void run() {
-        int[] temp;
-        temp = new int[1];
-
-        long t = java.lang.System.currentTimeMillis();
-
-        for (int i = 0; i < 1000000; i++)
-            mScript.forEach_root(ain, aout);
-        aout.copy1DRangeFrom(0, 1, temp);
-
-        t = java.lang.System.currentTimeMillis() - t;
-        android.util.Log.v("LatencyBench", "Iterated Java forEach took " + t + " ms");
-
-        mScript.set_empty_kern(mScript);
-        mScript.set_in(ain);
-        mScript.set_out(aout);
-
-        t = java.lang.System.currentTimeMillis();
-        mScript.invoke_emptyKernelLauncher();
-        aout.copy1DRangeFrom(0, 1, temp);
-
-        t = java.lang.System.currentTimeMillis() - t;
-        android.util.Log.v("LatencyBench", "Invoked forEach took " + t + " ms");
-
-
-
-    }
-
-}
diff --git a/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/LatencyBench.java b/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/LatencyBench.java
deleted file mode 100644
index fdce9a7..0000000
--- a/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/LatencyBench.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.latencybench;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.renderscript.RenderScript;
-
-public class LatencyBench extends Activity {
-    private RenderScript mRS;
-    private Benchmark mBenchmark;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        mRS = RenderScript.create(this);
-
-        mBenchmark = new Benchmark(mRS, getResources());
-        mBenchmark.run();
-    }
-}
diff --git a/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs b/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
deleted file mode 100644
index c6d1ea9..0000000
--- a/tests/RenderScriptTests/LatencyBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.latencybench)
-
-rs_script empty_kern;
-rs_allocation in, out;
-int iters = 1000000;
-
-void root(const uint32_t *ain, uint32_t *aout) {
-
-}
-
-void emptyKernelLauncher() {
-    for (int i = 0; i < iters; i++)
-        rsForEach(empty_kern, in, out);
-}
diff --git a/tests/RenderScriptTests/LivePreview/Android.mk b/tests/RenderScriptTests/LivePreview/Android.mk
deleted file mode 100644
index 1b45573..0000000
--- a/tests/RenderScriptTests/LivePreview/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := PreviewRS
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/LivePreview/AndroidManifest.xml b/tests/RenderScriptTests/LivePreview/AndroidManifest.xml
deleted file mode 100644
index 1b91464..0000000
--- a/tests/RenderScriptTests/LivePreview/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +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.
-*/
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.livepreview">
-    <uses-sdk android:minSdkVersion="14" />
-    <uses-permission android:name="android.permission.CAMERA" />
-    <application android:label="Preview FS"
-                 android:hardwareAccelerated="true">
-
-        <activity android:name="CameraPreviewActivity"
-                  android:label="Preview FS"
-                  android:screenOrientation="landscape">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/LivePreview/res/drawable-nodpi/city.png b/tests/RenderScriptTests/LivePreview/res/drawable-nodpi/city.png
deleted file mode 100644
index 856eeff..0000000
--- a/tests/RenderScriptTests/LivePreview/res/drawable-nodpi/city.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/LivePreview/res/layout/cf_format_list_item.xml b/tests/RenderScriptTests/LivePreview/res/layout/cf_format_list_item.xml
deleted file mode 100644
index 8196bbf..0000000
--- a/tests/RenderScriptTests/LivePreview/res/layout/cf_format_list_item.xml
+++ /dev/null
@@ -1,23 +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"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:padding="10dp"
-    android:textSize="16sp"
-/>
diff --git a/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml b/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml
deleted file mode 100644
index ecb736b..0000000
--- a/tests/RenderScriptTests/LivePreview/res/layout/cf_main.xml
+++ /dev/null
@@ -1,96 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent">
-
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="fill_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1" >
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="0dp"
-            android:layout_height="fill_parent"
-            android:layout_weight="3" >
-
-            <TextureView
-                android:id="@+id/preview_view"
-                android:layout_height="0dp"
-                android:layout_width="fill_parent"
-                android:layout_weight="3" />
-            <TextView
-                android:id="@+id/preview_label"
-                android:layout_height="wrap_content"
-                android:layout_width="fill_parent"
-                android:text="@string/cf_preview_label"
-                android:padding="2dp"
-                android:textSize="16sp"
-                android:gravity="center" />
-
-        </LinearLayout>
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="0dp"
-            android:layout_height="fill_parent"
-            android:layout_weight="3" >
-
-            <TextureView
-                android:id="@+id/format_view"
-                android:layout_height="0dp"
-                android:layout_width="fill_parent"
-                android:layout_weight="3" />
-            <TextView
-                android:id="@+id/format_label"
-                android:layout_height="wrap_content"
-                android:layout_width="fill_parent"
-                android:text="@string/cf_format_label"
-                android:padding="2dp"
-                android:textSize="16sp"
-                android:gravity="center" />
-
-        </LinearLayout>
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="0dp"
-            android:layout_height="fill_parent"
-            android:layout_weight="2" >
-
-            <Spinner
-                android:id="@+id/cameras_selection"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <Spinner
-                android:id="@+id/resolution_selection"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-            <Spinner
-                android:id="@+id/format_selection"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"/>
-
-        </LinearLayout>
-
-    </LinearLayout>
-
-
-</LinearLayout>
diff --git a/tests/RenderScriptTests/LivePreview/res/layout/main.xml b/tests/RenderScriptTests/LivePreview/res/layout/main.xml
deleted file mode 100644
index a6a075c..0000000
--- a/tests/RenderScriptTests/LivePreview/res/layout/main.xml
+++ /dev/null
@@ -1,140 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-            android:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:id="@+id/toplevel">
-    <SurfaceView
-        android:id="@+id/surface"
-        android:layout_width="1dip"
-        android:layout_height="1dip" />
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="vertical"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
-            <ImageView
-                android:id="@+id/display"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content" />
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-                    <Button
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/benchmark"
-                        android:onClick="benchmark"/>
-                    <TextView
-                        android:id="@+id/benchmarkText"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/saturation"/>
-            </LinearLayout>
-            <TextView
-                android:id="@+id/inSaturationText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/saturation"/>
-             <SeekBar
-                android:id="@+id/inSaturation"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/outWhiteText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:textSize="8pt"
-                android:text="@string/out_white"/>
-            <SeekBar
-                android:id="@+id/outWhite"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inWhiteText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/inWhite"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/outBlackText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/out_black"/>
-            <SeekBar
-                android:id="@+id/outBlack"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inBlackText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_black"/>
-            <SeekBar
-                android:id="@+id/inBlack"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inGammaText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/gamma"/>
-            <SeekBar
-                android:id="@+id/inGamma"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            </LinearLayout>
-    </ScrollView>
-</LinearLayout>
-
diff --git a/tests/RenderScriptTests/LivePreview/res/layout/rs.xml b/tests/RenderScriptTests/LivePreview/res/layout/rs.xml
deleted file mode 100644
index 6fde1b9..0000000
--- a/tests/RenderScriptTests/LivePreview/res/layout/rs.xml
+++ /dev/null
@@ -1,140 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-            android:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:id="@+id/toplevel">
-    <SurfaceView
-        android:id="@+id/surface"
-        android:layout_width="1dip"
-        android:layout_height="1dip" />
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="vertical"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
-            <TextureView
-                android:id="@+id/display"
-                android:layout_width="800sp"
-                android:layout_height="423sp" />
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-                    <Button
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/benchmark"
-                        android:onClick="benchmark"/>
-                    <TextView
-                        android:id="@+id/benchmarkText"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/saturation"/>
-            </LinearLayout>
-            <TextView
-                android:id="@+id/inSaturationText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/saturation"/>
-             <SeekBar
-                android:id="@+id/inSaturation"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/outWhiteText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:textSize="8pt"
-                android:text="@string/out_white"/>
-            <SeekBar
-                android:id="@+id/outWhite"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inWhiteText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_white"/>
-            <SeekBar
-                android:id="@+id/inWhite"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/outBlackText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/out_black"/>
-            <SeekBar
-                android:id="@+id/outBlack"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inBlackText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/in_black"/>
-            <SeekBar
-                android:id="@+id/inBlack"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/inGammaText"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="8pt"
-                android:layout_marginLeft="10sp"
-                android:layout_marginTop="15sp"
-                android:text="@string/gamma"/>
-            <SeekBar
-                android:id="@+id/inGamma"
-                android:layout_marginLeft="10sp"
-                android:layout_marginRight="10sp"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"/>
-            </LinearLayout>
-    </ScrollView>
-</LinearLayout>
-
diff --git a/tests/RenderScriptTests/LivePreview/res/values/strings.xml b/tests/RenderScriptTests/LivePreview/res/values/strings.xml
deleted file mode 100644
index d651bfb..0000000
--- a/tests/RenderScriptTests/LivePreview/res/values/strings.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <string name="in_white">In White</string>
-    <string name="out_white">Out White</string>
-    <string name="in_black">In Black</string>
-    <string name="out_black">Out Black</string>
-    <string name="gamma">Gamma</string>
-    <string name="saturation">Saturation</string>
-    <string name="benchmark">Benchmark</string>
-
-    <string name="app_name">CTS Verifier</string>
-    <string name="welcome_text">Welcome to the CTS Verifier!</string>
-    <string name="version_text">%1$s</string>
-    <string name="continue_button_text">Continue</string>
-
-    <string name="cf_preview_label">Normal preview</string>
-    <string name="cf_format_label">Processed callback data</string>
-    <string name="camera_format">Camera Formats</string>
-
-
-</resources>
diff --git a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java
deleted file mode 100644
index 62dcaa8..0000000
--- a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/CameraPreviewActivity.java
+++ /dev/null
@@ -1,374 +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 com.android.rs.livepreview;
-
-//import com.android.cts.verifier.PassFailButtons;
-//import com.android.cts.verifier.R;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.ImageFormat;
-import android.graphics.Matrix;
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.TextureView;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.Spinner;
-
-import java.io.IOException;
-import java.lang.InterruptedException;
-import java.lang.Math;
-import java.lang.Thread;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.TreeSet;
-
-import android.renderscript.*;
-
-/**
- * Tests for manual verification of the CDD-required camera output formats
- * for preview callbacks
- */
-public class CameraPreviewActivity extends Activity
-        implements TextureView.SurfaceTextureListener, Camera.PreviewCallback {
-
-    private static final String TAG = "CameraFormats";
-
-    private TextureView mPreviewView;
-    private SurfaceTexture mPreviewTexture;
-    private int mPreviewTexWidth;
-    private int mPreviewTexHeight;
-
-    //private TextureView mFormatView;
-
-    private Spinner mCameraSpinner;
-    private Spinner mResolutionSpinner;
-
-    private int mCurrentCameraId = -1;
-    private Camera mCamera;
-
-    private List<Camera.Size> mPreviewSizes;
-    private Camera.Size mNextPreviewSize;
-    private Camera.Size mPreviewSize;
-
-    private TextureView mOutputView;
-    //private Bitmap mCallbackBitmap;
-
-    private static final int STATE_OFF = 0;
-    private static final int STATE_PREVIEW = 1;
-    private static final int STATE_NO_CALLBACKS = 2;
-    private int mState = STATE_OFF;
-    private boolean mProcessInProgress = false;
-    private boolean mProcessingFirstFrame = false;
-
-
-    private RenderScript mRS;
-    private RsYuv mFilterYuv;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.cf_main);
-
-        mPreviewView = (TextureView) findViewById(R.id.preview_view);
-        mOutputView = (TextureView) findViewById(R.id.format_view);
-
-        mPreviewView.setSurfaceTextureListener(this);
-
-        int numCameras = Camera.getNumberOfCameras();
-        String[] cameraNames = new String[numCameras];
-        for (int i = 0; i < numCameras; i++) {
-            cameraNames[i] = "Camera " + i;
-        }
-        mCameraSpinner = (Spinner) findViewById(R.id.cameras_selection);
-        mCameraSpinner.setAdapter(
-            new ArrayAdapter<String>(
-                this, R.layout.cf_format_list_item, cameraNames));
-        mCameraSpinner.setOnItemSelectedListener(mCameraSpinnerListener);
-
-        mResolutionSpinner = (Spinner) findViewById(R.id.resolution_selection);
-        mResolutionSpinner.setOnItemSelectedListener(mResolutionSelectedListener);
-
-        mRS = RenderScript.create(this);
-        mFilterYuv = new RsYuv(mRS);
-        mOutputView.setSurfaceTextureListener(mFilterYuv);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        setUpCamera(mCameraSpinner.getSelectedItemPosition());
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-
-        shutdownCamera();
-    }
-
-    public void onSurfaceTextureAvailable(SurfaceTexture surface,
-            int width, int height) {
-        mPreviewTexture = surface;
-        mPreviewTexWidth = width;
-        mPreviewTexHeight = height;
-        if (mCamera != null) {
-            startPreview();
-        }
-    }
-
-    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
-        // Ignored, Camera does all the work for us
-    }
-
-    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-        return true;
-    }
-
-    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
-        // Invoked every time there's a new Camera preview frame
-    }
-
-    private AdapterView.OnItemSelectedListener mCameraSpinnerListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent,
-                        View view, int pos, long id) {
-                    if (mCurrentCameraId != pos) {
-                        setUpCamera(pos);
-                    }
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-
-            };
-
-    private AdapterView.OnItemSelectedListener mResolutionSelectedListener =
-            new AdapterView.OnItemSelectedListener() {
-                public void onItemSelected(AdapterView<?> parent,
-                        View view, int position, long id) {
-                    if (mPreviewSizes.get(position) != mPreviewSize) {
-                        mNextPreviewSize = mPreviewSizes.get(position);
-                        startPreview();
-                    }
-                }
-
-                public void onNothingSelected(AdapterView parent) {
-
-                }
-
-            };
-
-
-    private void setUpCamera(int id) {
-        shutdownCamera();
-
-        mCurrentCameraId = id;
-        mCamera = Camera.open(id);
-        Camera.Parameters p = mCamera.getParameters();
-
-        // Get preview resolutions
-
-        List<Camera.Size> unsortedSizes = p.getSupportedPreviewSizes();
-
-        class SizeCompare implements Comparator<Camera.Size> {
-            public int compare(Camera.Size lhs, Camera.Size rhs) {
-                if (lhs.width < rhs.width) return -1;
-                if (lhs.width > rhs.width) return 1;
-                if (lhs.height < rhs.height) return -1;
-                if (lhs.height > rhs.height) return 1;
-                return 0;
-            }
-        };
-
-        SizeCompare s = new SizeCompare();
-        TreeSet<Camera.Size> sortedResolutions = new TreeSet<Camera.Size>(s);
-        sortedResolutions.addAll(unsortedSizes);
-
-        mPreviewSizes = new ArrayList<Camera.Size>(sortedResolutions);
-
-        String[] availableSizeNames = new String[mPreviewSizes.size()];
-        for (int i = 0; i < mPreviewSizes.size(); i++) {
-            availableSizeNames[i] =
-                    Integer.toString(mPreviewSizes.get(i).width) + " x " +
-                    Integer.toString(mPreviewSizes.get(i).height);
-        }
-        mResolutionSpinner.setAdapter(
-            new ArrayAdapter<String>(
-                this, R.layout.cf_format_list_item, availableSizeNames));
-
-
-        // Set initial values
-
-        mNextPreviewSize = mPreviewSizes.get(15);
-        mResolutionSpinner.setSelection(15);
-
-        if (mPreviewTexture != null) {
-            startPreview();
-        }
-    }
-
-    private void shutdownCamera() {
-        if (mCamera != null) {
-            mCamera.setPreviewCallbackWithBuffer(null);
-            mCamera.stopPreview();
-            mCamera.release();
-            mCamera = null;
-            mState = STATE_OFF;
-        }
-    }
-
-    private void startPreview() {
-        if (mState != STATE_OFF) {
-            // Stop for a while to drain callbacks
-            mCamera.setPreviewCallbackWithBuffer(null);
-            mCamera.stopPreview();
-            mState = STATE_OFF;
-            Handler h = new Handler();
-            Runnable mDelayedPreview = new Runnable() {
-                public void run() {
-                    startPreview();
-                }
-            };
-            h.postDelayed(mDelayedPreview, 300);
-            return;
-        }
-        mState = STATE_PREVIEW;
-
-        Matrix transform = new Matrix();
-        float widthRatio = mNextPreviewSize.width / (float)mPreviewTexWidth;
-        float heightRatio = mNextPreviewSize.height / (float)mPreviewTexHeight;
-
-        transform.setScale(1, heightRatio/widthRatio);
-        transform.postTranslate(0,
-                mPreviewTexHeight * (1 - heightRatio/widthRatio)/2);
-
-        mPreviewView.setTransform(transform);
-        mOutputView.setTransform(transform);
-
-        mPreviewSize   = mNextPreviewSize;
-
-        Camera.Parameters p = mCamera.getParameters();
-        p.setPreviewFormat(ImageFormat.NV21);
-        p.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
-        mCamera.setParameters(p);
-
-        mCamera.setPreviewCallbackWithBuffer(this);
-        int expectedBytes = mPreviewSize.width * mPreviewSize.height *
-                ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
-        for (int i=0; i < 4; i++) {
-            mCamera.addCallbackBuffer(new byte[expectedBytes]);
-        }
-        //mFormatView.setColorFilter(mYuv2RgbFilter);
-
-        mProcessingFirstFrame = true;
-        try {
-            mCamera.setPreviewTexture(mPreviewTexture);
-            mCamera.startPreview();
-        } catch (IOException ioe) {
-            // Something bad happened
-            Log.e(TAG, "Unable to start up preview");
-        }
-
-    }
-
-
-    private class ProcessPreviewDataTask extends AsyncTask<byte[], Void, Boolean> {
-        protected Boolean doInBackground(byte[]... datas) {
-            byte[] data = datas[0];
-
-            long t1 = java.lang.System.currentTimeMillis();
-
-            mFilterYuv.execute(data);
-
-            long t2 = java.lang.System.currentTimeMillis();
-            mTiming[mTimingSlot++] = t2 - t1;
-            if (mTimingSlot >= mTiming.length) {
-                float total = 0;
-                for (int i=0; i<mTiming.length; i++) {
-                    total += (float)mTiming[i];
-                }
-                total /= mTiming.length;
-                Log.e(TAG, "time + " + total);
-                mTimingSlot = 0;
-            }
-
-            mCamera.addCallbackBuffer(data);
-            mProcessInProgress = false;
-            return true;
-        }
-
-        protected void onPostExecute(Boolean result) {
-            mOutputView.invalidate();
-        }
-
-    }
-
-    private long mTiming[] = new long[50];
-    private int mTimingSlot = 0;
-
-    public void onPreviewFrame(byte[] data, Camera camera) {
-        if (mProcessInProgress || mState != STATE_PREVIEW) {
-            mCamera.addCallbackBuffer(data);
-            return;
-        }
-        if (data == null) {
-            return;
-        }
-
-        int expectedBytes = mPreviewSize.width * mPreviewSize.height *
-                ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
-
-        if (expectedBytes != data.length) {
-            Log.e(TAG, "Mismatched size of buffer! Expected ");
-
-            mState = STATE_NO_CALLBACKS;
-            mCamera.setPreviewCallbackWithBuffer(null);
-            return;
-        }
-
-        mProcessInProgress = true;
-
-        if ((mFilterYuv == null) ||
-            (mPreviewSize.width != mFilterYuv.getWidth()) ||
-            (mPreviewSize.height != mFilterYuv.getHeight()) ) {
-
-            mFilterYuv.reset(mPreviewSize.width, mPreviewSize.height);
-        }
-
-        mProcessInProgress = true;
-        new ProcessPreviewDataTask().execute(data);
-    }
-
-
-
-}
\ No newline at end of file
diff --git a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java
deleted file mode 100644
index 12d3185..0000000
--- a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/RsYuv.java
+++ /dev/null
@@ -1,151 +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 com.android.rs.livepreview;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.os.Bundle;
-import android.graphics.SurfaceTexture;
-import android.renderscript.Allocation;
-import android.renderscript.Matrix3f;
-import android.renderscript.RenderScript;
-import android.util.Log;
-import android.view.TextureView;
-import android.view.View;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-
-import android.graphics.Bitmap;
-
-public class RsYuv implements TextureView.SurfaceTextureListener
-{
-    private int mHeight;
-    private int mWidth;
-    private RenderScript mRS;
-    private Allocation mAllocationOut;
-    private Allocation mAllocationIn;
-    private ScriptC_yuv mScript;
-    private ScriptIntrinsicYuvToRGB mYuv;
-    private boolean mHaveSurface;
-    private SurfaceTexture mSurface;
-    private ScriptGroup mGroup;
-
-    RsYuv(RenderScript rs) {
-        mRS = rs;
-        mScript = new ScriptC_yuv(mRS);
-        mYuv = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(mRS));
-    }
-
-    void setupSurface() {
-        if (mAllocationOut != null) {
-            mAllocationOut.setSurfaceTexture(mSurface);
-        }
-        if (mSurface != null) {
-            mHaveSurface = true;
-        } else {
-            mHaveSurface = false;
-        }
-    }
-
-    void reset(int width, int height) {
-        if (mAllocationOut != null) {
-            mAllocationOut.destroy();
-        }
-
-        android.util.Log.v("cpa", "reset " + width + ", " + height);
-        mHeight = height;
-        mWidth = width;
-        mScript.invoke_setSize(mWidth, mHeight);
-
-        Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        tb.setX(mWidth);
-        tb.setY(mHeight);
-        Type t = tb.create();
-        mAllocationOut = Allocation.createTyped(mRS, t, Allocation.USAGE_SCRIPT |
-                                                        Allocation.USAGE_IO_OUTPUT);
-
-
-        tb = new Type.Builder(mRS, Element.createPixel(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.PIXEL_YUV));
-        tb.setX(mWidth);
-        tb.setY(mHeight);
-        tb.setYuvFormat(android.graphics.ImageFormat.NV21);
-        mAllocationIn = Allocation.createTyped(mRS, tb.create(), Allocation.USAGE_SCRIPT);
-        mYuv.setInput(mAllocationIn);
-        setupSurface();
-
-
-        ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
-        b.addKernel(mScript.getKernelID_root());
-        b.addKernel(mYuv.getKernelID());
-        b.addConnection(t, mYuv.getKernelID(), mScript.getKernelID_root());
-        mGroup = b.create();
-    }
-
-    public int getWidth() {
-        return mWidth;
-    }
-    public int getHeight() {
-        return mHeight;
-    }
-
-    private long mTiming[] = new long[50];
-    private int mTimingSlot = 0;
-
-    void execute(byte[] yuv) {
-        mAllocationIn.copyFrom(yuv);
-        if (mHaveSurface) {
-            mGroup.setOutput(mScript.getKernelID_root(), mAllocationOut);
-            mGroup.execute();
-
-            //mYuv.forEach(mAllocationOut);
-            //mScript.forEach_root(mAllocationOut, mAllocationOut);
-            mAllocationOut.ioSendOutput();
-        }
-    }
-
-
-
-    @Override
-    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
-        android.util.Log.v("cpa", "onSurfaceTextureAvailable " + surface);
-        mSurface = surface;
-        setupSurface();
-    }
-
-    @Override
-    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
-        android.util.Log.v("cpa", "onSurfaceTextureSizeChanged " + surface);
-        mSurface = surface;
-        setupSurface();
-    }
-
-    @Override
-    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-        android.util.Log.v("cpa", "onSurfaceTextureDestroyed " + surface);
-        mSurface = surface;
-        setupSurface();
-        return true;
-    }
-
-    @Override
-    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
-    }
-}
-
diff --git a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs b/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs
deleted file mode 100644
index c4f698f..0000000
--- a/tests/RenderScriptTests/LivePreview/src/com/android/rs/livepreview/yuv.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.livepreview)
-//#pragma rs_fp_relaxed
-
-static int gWidth;
-static int gHeight;
-static uchar crossProcess_tableR[256];
-static uchar crossProcess_tableG[256];
-static uchar crossProcess_tableB[256];
-static uchar vignette_table[512];
-
-
-static float4 crossProcess(float4 color) {
-    float4 ncolor = 0.f;
-    float v;
-
-    if (color.r < 0.5f) {
-        v = color.r;
-        ncolor.r = 4.0f * v * v * v;
-    } else {
-        v = 1.0f - color.r;
-        ncolor.r = 1.0f - (4.0f * v * v * v);
-    }
-
-    if (color.g < 0.5f) {
-        v = color.g;
-        ncolor.g = 2.0f * v * v;
-    } else {
-        v = 1.0f - color.g;
-        ncolor.g = 1.0f - (2.0f * v * v);
-    }
-
-    ncolor.b = color.b * 0.5f + 0.25f;
-    ncolor.a = color.a;
-    return ncolor;
-}
-
-static uchar4 crossProcess_i(uchar4 color) {
-    uchar4 ncolor = color;
-    ncolor.r = crossProcess_tableR[color.r];
-    ncolor.g = crossProcess_tableG[color.g];
-    ncolor.b = crossProcess_tableB[color.b];
-    return ncolor;
-}
-
-
-float temp = 0.2f;
-static float4 colortemp(float4 color) {
-    float4 new_color = color;
-    float4 t = color * ((float4)1.0f - color) * temp;
-
-    new_color.r = color.r + t.r;
-    new_color.b = color.b - t.b;
-    if (temp > 0.0f) {
-        color.g = color.g + t.g * 0.25f;
-    }
-    float max_value = max(new_color.r, max(new_color.g, new_color.b));
-    if (max_value > 1.0f) {
-        new_color /= max_value;
-    }
-
-    return new_color;
-}
-
-
-static float vignette_dist_mod;
-int2 vignette_half_dims;
-static uchar4 vignette(uchar4 color, uint32_t x, uint32_t y) {
-    int2 xy = {x, y};
-    xy -= vignette_half_dims;
-    xy *= xy;
-
-    float d = vignette_dist_mod * (xy.x + xy.y);
-    ushort4 c = convert_ushort4(color);
-    c *= vignette_table[(int)d];
-    c >>= (ushort4)8;
-    return convert_uchar4(c);
-}
-
-void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
-    uchar4 p;
-    p = crossProcess_i(*in);
-    p = vignette(p, x, y);
-
-    out->rgba = p;
-    out->a = 0xff;
-}
-
-float vignetteScale = 0.5f;
-float vignetteShade = 0.85f;
-
-static void precompute() {
-    for(int i=0; i <256; i++) {
-        float4 f = ((float)i) / 255.f;
-        float4 res = crossProcess(f);
-        res = colortemp(res);
-        crossProcess_tableR[i] = (uchar)(res.r * 255.f);
-        crossProcess_tableG[i] = (uchar)(res.g * 255.f);
-        crossProcess_tableB[i] = (uchar)(res.b * 255.f);
-    }
-
-    for(int i=0; i <512; i++) {
-        const float slope = 20.0f;
-        float f = ((float)i) / 511.f;
-
-        float range = 1.30f - sqrt(vignetteScale) * 0.7f;
-        float lumen = vignetteShade / (1.0f + exp((sqrt(f) - range) * slope)) + (1.0f - vignetteShade);
-        lumen = clamp(lumen, 0.f, 1.f);
-
-        vignette_table[i] = (uchar)(lumen * 255.f + 0.5f);
-    }
-}
-
-void init() {
-    precompute();
-}
-
-void setSize(int w, int h) {
-    gWidth = w;
-    gHeight = h;
-    vignette_half_dims = (int2){w / 2, h / 2};
-    vignette_dist_mod = 512.f;
-    vignette_dist_mod /= (float)(w*w + h*h) / 4.f;
-
-}
diff --git a/tests/RenderScriptTests/MathErr/Android.mk b/tests/RenderScriptTests/MathErr/Android.mk
deleted file mode 100644
index b3edd02..0000000
--- a/tests/RenderScriptTests/MathErr/Android.mk
+++ /dev/null
@@ -1,27 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-                   $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RsMathErr
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/MathErr/AndroidManifest.xml b/tests/RenderScriptTests/MathErr/AndroidManifest.xml
deleted file mode 100644
index 6a3db2c..0000000
--- a/tests/RenderScriptTests/MathErr/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.matherr">
-
-    <uses-sdk android:minSdkVersion="17" />
-    <application android:label="RS Math Err">
-        <activity android:name="MathErrActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/MathErr/res/layout/main.xml b/tests/RenderScriptTests/MathErr/res/layout/main.xml
deleted file mode 100644
index 7b2c76a..0000000
--- a/tests/RenderScriptTests/MathErr/res/layout/main.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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">
-
-    <ImageView
-        android:id="@+id/displayin"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-    <ImageView
-        android:id="@+id/displayout"
-        android:layout_width="320dip"
-        android:layout_height="266dip" />
-
-</LinearLayout>
diff --git a/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/MathErr.java b/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/MathErr.java
deleted file mode 100644
index 4561267..0000000
--- a/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/MathErr.java
+++ /dev/null
@@ -1,86 +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 com.example.android.rs.matherr;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import java.lang.Float;
-import java.lang.Math;
-
-public class MathErr {
-    private RenderScript mRS;
-    private Allocation mAllocationSrc;
-    private Allocation mAllocationRes;
-    private ScriptC_math_err mScript;
-    private java.util.Random mRand = new java.util.Random();
-
-    private final int BUF_SIZE = 4096;
-    float mSrc[] = new float[BUF_SIZE];
-    float mRef[] = new float[BUF_SIZE];
-    float mRes[] = new float[BUF_SIZE];
-
-    MathErr(RenderScript rs) {
-        mRS = rs;
-        mScript = new ScriptC_math_err(mRS);
-
-        mAllocationSrc = Allocation.createSized(rs, Element.F32(rs), BUF_SIZE);
-        mAllocationRes = Allocation.createSized(rs, Element.F32(rs), BUF_SIZE);
-
-        testExp2();
-        testLog2();
-    }
-
-    void buildRand() {
-        for (int i=0; i < BUF_SIZE; i++) {
-            mSrc[i] = (((float)i) / 9) - 200;
-            //mSrc[i] = Float.intBitsToFloat(mRand.nextInt());
-        }
-        mAllocationSrc.copyFrom(mSrc);
-    }
-
-    void logErr() {
-        mAllocationRes.copyTo(mRes);
-        for (int i=0; i < BUF_SIZE; i++) {
-            int err = Float.floatToRawIntBits(mRef[i]) - Float.floatToRawIntBits(mRes[i]);
-            err = Math.abs(err);
-            if (err > 8096) {
-                android.util.Log.v("err", "error " + err + " src " + mSrc[i] + " ref " + mRef[i] + " res " + mRes[i]);
-            }
-        }
-    }
-
-    void testExp2() {
-        android.util.Log.v("err", "testing exp2");
-        buildRand();
-        mScript.forEach_testExp2(mAllocationSrc, mAllocationRes);
-        for (int i=0; i < BUF_SIZE; i++) {
-            mRef[i] = (float)Math.pow(2.f, mSrc[i]);
-        }
-        logErr();
-    }
-
-    void testLog2() {
-        android.util.Log.v("err", "testing log2");
-        buildRand();
-        mScript.forEach_testLog2(mAllocationSrc, mAllocationRes);
-        for (int i=0; i < BUF_SIZE; i++) {
-            mRef[i] = (float)Math.log(mSrc[i]) * 1.442695041f;
-        }
-        logErr();
-    }
-
-}
diff --git a/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/MathErrActivity.java b/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/MathErrActivity.java
deleted file mode 100644
index 74d7b71..0000000
--- a/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/MathErrActivity.java
+++ /dev/null
@@ -1,37 +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 com.example.android.rs.matherr;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.renderscript.RenderScript;
-import android.renderscript.Allocation;
-import android.util.Log;
-
-public class MathErrActivity extends Activity {
-    private MathErr mME;
-    private RenderScript mRS;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.main);
-
-        mRS = RenderScript.create(this);
-        mME = new MathErr(mRS);
-    }
-}
diff --git a/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/math_err.rs b/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/math_err.rs
deleted file mode 100644
index a26770b..0000000
--- a/tests/RenderScriptTests/MathErr/src/com/example/android/rs/matherr/math_err.rs
+++ /dev/null
@@ -1,84 +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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.example.android.rs.matherr)
-
-typedef union
-{
-  float fv;
-  int32_t iv;
-} ieee_float_shape_type;
-
-/* Get a 32 bit int from a float.  */
-
-#define GET_FLOAT_WORD(i,d)         \
-do {                                \
-  ieee_float_shape_type gf_u;       \
-  gf_u.fv = (d);                    \
-  (i) = gf_u.iv;                    \
-} while (0)
-
-/* Set a float from a 32 bit int.  */
-
-#define SET_FLOAT_WORD(d,i)         \
-do {                                \
-  ieee_float_shape_type sf_u;       \
-  sf_u.iv = (i);                    \
-  (d) = sf_u.fv;                    \
-} while (0)
-
-
-static float fast_log2(float v) {
-    int32_t ibits;
-    GET_FLOAT_WORD(ibits, v);
-
-    int32_t e = (ibits >> 23) & 0xff;
-
-    ibits &= 0x7fffff;
-    ibits |= 127 << 23;
-
-    float ir;
-    SET_FLOAT_WORD(ir, ibits);
-
-    ir -= 1.5f;
-    float ir2 = ir*ir;
-    float adj2 = 0.405465108f + // -0.00009f +
-                 (0.666666667f * ir) -
-                 (0.222222222f * ir2) +
-                 (0.098765432f * ir*ir2) -
-                 (0.049382716f * ir2*ir2) +
-                 (0.026337449f * ir*ir2*ir2) -
-                 (0.014631916f * ir2*ir2*ir2);
-    adj2 *= (1.f / 0.693147181f);
-
-    return (float)(e - 127) + adj2;
-}
-
-void testExp2(const float *in, float *out) {
-    float i = *in;
-    if (i > (-125.f) && i < 125.f) {
-        *out = native_exp2(i);
-    } else {
-        *out = exp2(i);
-    }
-    *out = native_exp2(i);
-}
-
-void testLog2(const float *in, float *out) {
-    *out = fast_log2(*in);
-}
-
diff --git a/tests/RenderScriptTests/MiscSamples/Android.mk b/tests/RenderScriptTests/MiscSamples/Android.mk
index bdff46a..ee3567b 100644
--- a/tests/RenderScriptTests/MiscSamples/Android.mk
+++ b/tests/RenderScriptTests/MiscSamples/Android.mk
@@ -23,6 +23,6 @@
 
 LOCAL_PACKAGE_NAME := RsMiscSamples
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 17
 
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ModelViewer/Android.mk b/tests/RenderScriptTests/ModelViewer/Android.mk
index 18ceac5..86724cf 100644
--- a/tests/RenderScriptTests/ModelViewer/Android.mk
+++ b/tests/RenderScriptTests/ModelViewer/Android.mk
@@ -22,6 +22,8 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
 
+LOCAL_SDK_VERSION := 17
+
 LOCAL_PACKAGE_NAME := ModelViewer
 
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/PerfTest/Android.mk b/tests/RenderScriptTests/PerfTest/Android.mk
index 0d1e7d2..e9ee771 100644
--- a/tests/RenderScriptTests/PerfTest/Android.mk
+++ b/tests/RenderScriptTests/PerfTest/Android.mk
@@ -24,6 +24,8 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 #LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
 
+LOCAL_SDK_VERSION := 17
+
 LOCAL_PACKAGE_NAME := PerfTest
 
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/Android.mk b/tests/RenderScriptTests/RSTest_CompatLib/Android.mk
deleted file mode 100644
index 0fd0d96..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/Android.mk
+++ /dev/null
@@ -1,40 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RSTest_Compat
-
-LOCAL_STATIC_JAVA_LIBRARIES := android.support.v8.renderscript
-
-LOCAL_SDK_VERSION := 8
-LOCAL_RENDERSCRIPT_TARGET_API := 18
-LOCAL_RENDERSCRIPT_COMPATIBILITY := 18
-
-LOCAL_RENDERSCRIPT_CC := $(LLVM_RS_CC)
-LOCAL_RENDERSCRIPT_INCLUDES_OVERRIDE := \
-    $(TOPDIR)external/clang/lib/Headers \
-    $(TOPDIR)frameworks/rs/scriptc
-
-LOCAL_RENDERSCRIPT_FLAGS := -rs-package-name=android.support.v8.renderscript
-LOCAL_REQUIRED_MODULES := librsjni
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/AndroidManifest.xml b/tests/RenderScriptTests/RSTest_CompatLib/AndroidManifest.xml
deleted file mode 100644
index 53219e7..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.test_compat">
-  <uses-sdk android:minSdkVersion="8" />
-  <uses-sdk android:targetSdkVersion="8" />
-    <application
-        android:label="_RS_Test_Compat"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="RSTest"
-                  android:screenOrientation="portrait">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/RSTest_CompatLib/res/drawable-nodpi/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/res/drawable-nodpi/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/RSTest.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/RSTest.java
deleted file mode 100644
index b76f21e..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/RSTest.java
+++ /dev/null
@@ -1,70 +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 com.android.rs.test_compat;
-
-import android.support.v8.renderscript.RenderScript;
-
-import android.app.ListActivity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.ArrayAdapter;
-
-import java.lang.Runtime;
-
-public class RSTest extends ListActivity {
-
-    private static final String LOG_TAG = "RSTest_Compat";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private RenderScript mRS;
-    private RSTestCore RSTC;
-
-    String mTestNames[];
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        mRS = RenderScript.create(this);
-
-        RSTC = new RSTestCore(this);
-        RSTC.init(mRS, getResources());
-
-
-
-
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/RSTestCore.java
deleted file mode 100644
index 51f8a4d..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/RSTestCore.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2008-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.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.ListIterator;
-import java.util.Timer;
-import java.util.TimerTask;
-import android.app.ListActivity;
-import android.widget.ArrayAdapter;
-
-public class RSTestCore {
-    ListActivity mCtx;
-
-    public RSTestCore(ListActivity ctx) {
-        mCtx = ctx;
-    }
-
-    private Resources mRes;
-    private RenderScript mRS;
-
-    private ArrayList<UnitTest> unitTests;
-    private ListIterator<UnitTest> test_iter;
-    private UnitTest activeTest;
-    private boolean stopTesting;
-
-    private ScriptField_ListAllocs_s mListAllocs;
-
-    private ArrayAdapter<UnitTest> testAdapter;
-
-    /* Periodic timer for ensuring future tests get scheduled */
-    private Timer mTimer;
-    public static final int RS_TIMER_PERIOD = 100;
-
-    public void init(RenderScript rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-        stopTesting = false;
-
-        unitTests = new ArrayList<UnitTest>();
-
-        unitTests.add(new UT_primitives(this, mRes, mCtx));
-        unitTests.add(new UT_constant(this, mRes, mCtx));
-        unitTests.add(new UT_vector(this, mRes, mCtx));
-        unitTests.add(new UT_unsigned(this, mRes, mCtx));
-        unitTests.add(new UT_array_init(this, mRes, mCtx));
-        unitTests.add(new UT_array_alloc(this, mRes, mCtx));
-        unitTests.add(new UT_kernel(this, mRes, mCtx));
-        unitTests.add(new UT_kernel_struct(this, mRes, mCtx));
-        unitTests.add(new UT_bug_char(this, mRes, mCtx));
-        unitTests.add(new UT_clamp(this, mRes, mCtx));
-        unitTests.add(new UT_clamp_relaxed(this, mRes, mCtx));
-        unitTests.add(new UT_convert(this, mRes, mCtx));
-        unitTests.add(new UT_convert_relaxed(this, mRes, mCtx));
-        unitTests.add(new UT_copy_test(this, mRes, mCtx));
-        unitTests.add(new UT_rsdebug(this, mRes, mCtx));
-        unitTests.add(new UT_rstime(this, mRes, mCtx));
-        unitTests.add(new UT_rstypes(this, mRes, mCtx));
-        unitTests.add(new UT_alloc(this, mRes, mCtx));
-        unitTests.add(new UT_refcount(this, mRes, mCtx));
-        unitTests.add(new UT_foreach(this, mRes, mCtx));
-        unitTests.add(new UT_foreach_bounds(this, mRes, mCtx));
-        unitTests.add(new UT_noroot(this, mRes, mCtx));
-        unitTests.add(new UT_atomic(this, mRes, mCtx));
-        unitTests.add(new UT_struct(this, mRes, mCtx));
-        unitTests.add(new UT_math(this, mRes, mCtx));
-        unitTests.add(new UT_math_conformance(this, mRes, mCtx));
-        unitTests.add(new UT_math_agree(this, mRes, mCtx));
-        unitTests.add(new UT_min(this, mRes, mCtx));
-        unitTests.add(new UT_int4(this, mRes, mCtx));
-        unitTests.add(new UT_element(this, mRes, mCtx));
-        unitTests.add(new UT_sampler(this, mRes, mCtx));
-        unitTests.add(new UT_fp_mad(this, mRes, mCtx));
-
-        /*
-        unitTests.add(new UnitTest(null, "<Pass>", 1));
-        unitTests.add(new UnitTest());
-        unitTests.add(new UnitTest(null, "<Fail>", -1));
-
-        for (int i = 0; i < 20; i++) {
-            unitTests.add(new UnitTest(null, "<Pass>", 1));
-        }
-        */
-
-        UnitTest [] uta = new UnitTest[unitTests.size()];
-        uta = unitTests.toArray(uta);
-
-        mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length);
-        for (int i = 0; i < uta.length; i++) {
-
-            ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
-            listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
-            listElem.result = uta[i].getResult();
-            mListAllocs.set(listElem, i, false);
-            uta[i].setItem(listElem);
-        }
-
-        mListAllocs.copyAll();
-
-        testAdapter = new ArrayAdapter<UnitTest>(mCtx, android.R.layout.simple_list_item_1, unitTests);
-        mCtx.setListAdapter(testAdapter);
-
-        test_iter = unitTests.listIterator();
-        refreshTestResults(); /* Kick off the first test */
-
-        TimerTask pTask = new TimerTask() {
-            public void run() {
-                refreshTestResults();
-            }
-        };
-
-        mTimer = new Timer();
-        mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD);
-    }
-
-    public void checkAndRunNextTest() {
-        mCtx.runOnUiThread(new Runnable() {
-                public void run() {
-                    if (testAdapter != null)
-                        testAdapter.notifyDataSetChanged();
-                }
-            });
-
-        if (activeTest != null) {
-            if (!activeTest.isAlive()) {
-                /* Properly clean up on our last test */
-                try {
-                    activeTest.join();
-                }
-                catch (InterruptedException e) {
-                }
-                activeTest = null;
-            }
-        }
-
-        if (!stopTesting && activeTest == null) {
-            if (test_iter.hasNext()) {
-                activeTest = test_iter.next();
-                activeTest.start();
-                /* This routine will only get called once when a new test
-                 * should start running. The message handler in UnitTest.java
-                 * ensures this. */
-            }
-            else {
-                if (mTimer != null) {
-                    mTimer.cancel();
-                    mTimer.purge();
-                    mTimer = null;
-                }
-            }
-        }
-    }
-
-    public void refreshTestResults() {
-        checkAndRunNextTest();
-    }
-
-    public void cleanup() {
-        stopTesting = true;
-        UnitTest t = activeTest;
-
-        /* Stop periodic refresh of testing */
-        if (mTimer != null) {
-            mTimer.cancel();
-            mTimer.purge();
-            mTimer = null;
-        }
-
-        /* Wait to exit until we finish the current test */
-        if (t != null) {
-            try {
-                t.join();
-            }
-            catch (InterruptedException e) {
-            }
-            t = null;
-        }
-
-    }
-
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
deleted file mode 100644
index 3af3745..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_alloc.java
+++ /dev/null
@@ -1,69 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_alloc extends UnitTest {
-    private Resources mRes;
-
-    protected UT_alloc(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Alloc", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_alloc s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        int Z = 0;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        s.set_dimZ(Z);
-        typeBuilder.setX(X).setY(Y);
-        Allocation A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
-        s.set_aRaw(A);
-
-        typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        typeBuilder.setX(X).setY(Y).setFaces(true);
-        Allocation AFaces = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aFaces(AFaces);
-        typeBuilder.setFaces(false).setMipmaps(true);
-        Allocation ALOD = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aLOD(ALOD);
-        typeBuilder.setFaces(true).setMipmaps(true);
-        Allocation AFacesLOD = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aFacesLOD(AFacesLOD);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_alloc s = new ScriptC_alloc(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_root(s.get_aRaw());
-        s.invoke_alloc_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_array_alloc.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_array_alloc.java
deleted file mode 100644
index 751187b..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_array_alloc.java
+++ /dev/null
@@ -1,52 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_array_alloc extends UnitTest {
-    private Resources mRes;
-
-    protected UT_array_alloc(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Array Allocation", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_array_alloc s = new ScriptC_array_alloc(pRS);
-        pRS.setMessageHandler(mRsMessage);
-
-        int dimX = s.get_dimX();
-        Allocation[] Arr = new Allocation[dimX];
-        Type.Builder typeBuilder = new Type.Builder(pRS, Element.I32(pRS));
-        Type T = typeBuilder.setX(1).create();
-        for (int i = 0; i < dimX; i++) {
-            Allocation A = Allocation.createTyped(pRS, T);
-            Arr[i] = A;
-        }
-        s.set_a(Arr);
-
-        s.invoke_array_alloc_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_array_init.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_array_init.java
deleted file mode 100644
index f8b2fd3..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_array_init.java
+++ /dev/null
@@ -1,95 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_array_init extends UnitTest {
-    private Resources mRes;
-
-    protected UT_array_init(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Array Init", ctx);
-        mRes = res;
-    }
-
-    private void checkInit(ScriptC_array_init s) {
-        float[] fa = s.get_fa();
-        _RS_ASSERT("fa[0] == 1.0", fa[0] == 1.0);
-        _RS_ASSERT("fa[1] == 9.9999f", fa[1] == 9.9999f);
-        _RS_ASSERT("fa[2] == 0", fa[2] == 0);
-        _RS_ASSERT("fa[3] == 0", fa[3] == 0);
-        _RS_ASSERT("fa.length == 4", fa.length == 4);
-
-        double[] da = s.get_da();
-        _RS_ASSERT("da[0] == 7.0", da[0] == 7.0);
-        _RS_ASSERT("da[1] == 8.88888", da[1] == 8.88888);
-        _RS_ASSERT("da.length == 2", da.length == 2);
-
-        byte[] ca = s.get_ca();
-        _RS_ASSERT("ca[0] == 'a'", ca[0] == 'a');
-        _RS_ASSERT("ca[1] == 7", ca[1] == 7);
-        _RS_ASSERT("ca[2] == 'b'", ca[2] == 'b');
-        _RS_ASSERT("ca[3] == 'c'", ca[3] == 'c');
-        _RS_ASSERT("ca.length == 4", ca.length == 4);
-
-        short[] sa = s.get_sa();
-        _RS_ASSERT("sa[0] == 1", sa[0] == 1);
-        _RS_ASSERT("sa[1] == 1", sa[1] == 1);
-        _RS_ASSERT("sa[2] == 2", sa[2] == 2);
-        _RS_ASSERT("sa[3] == 3", sa[3] == 3);
-        _RS_ASSERT("sa.length == 4", sa.length == 4);
-
-        int[] ia = s.get_ia();
-        _RS_ASSERT("ia[0] == 5", ia[0] == 5);
-        _RS_ASSERT("ia[1] == 8", ia[1] == 8);
-        _RS_ASSERT("ia[2] == 0", ia[2] == 0);
-        _RS_ASSERT("ia[3] == 0", ia[3] == 0);
-        _RS_ASSERT("ia.length == 4", ia.length == 4);
-
-        long[] la = s.get_la();
-        _RS_ASSERT("la[0] == 13", la[0] == 13);
-        _RS_ASSERT("la[1] == 21", la[1] == 21);
-        _RS_ASSERT("la.length == 4", la.length == 2);
-
-        long[] lla = s.get_lla();
-        _RS_ASSERT("lla[0] == 34", lla[0] == 34);
-        _RS_ASSERT("lla[1] == 0", lla[1] == 0);
-        _RS_ASSERT("lla[2] == 0", lla[2] == 0);
-        _RS_ASSERT("lla[3] == 0", lla[3] == 0);
-        _RS_ASSERT("lla.length == 4", lla.length == 4);
-
-        boolean[] ba = s.get_ba();
-        _RS_ASSERT("ba[0] == true", ba[0] == true);
-        _RS_ASSERT("ba[1] == false", ba[1] == false);
-        _RS_ASSERT("ba[2] == false", ba[2] == false);
-        _RS_ASSERT("ba.length == 3", ba.length == 3);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_array_init s = new ScriptC_array_init(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        checkInit(s);
-        s.invoke_array_init_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_atomic.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_atomic.java
deleted file mode 100644
index 7fe4b36..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_atomic.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_atomic extends UnitTest {
-    private Resources mRes;
-
-    protected UT_atomic(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Atomics", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_atomic s = new ScriptC_atomic(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_atomic_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_bug_char.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_bug_char.java
deleted file mode 100644
index 5da5288..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_bug_char.java
+++ /dev/null
@@ -1,89 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import java.util.Arrays;
-
-public class UT_bug_char extends UnitTest {
-    private Resources mRes;
-
-    protected UT_bug_char(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Bug Char", ctx);
-        mRes = res;
-    }
-
-    // packing functions
-    private Byte2 pack_b2(byte[] val) {
-        assert val.length == 2;
-        Log.i("bug_char", "pack_b2 " + val[0] + " " + val[1]);
-        return new Byte2(val[0], val[1]);
-    }
-
-    private byte min(byte v1, byte v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private byte[] min(byte[] v1, byte[] v2) {
-        assert v1.length == v2.length;
-        byte[] rv = new byte[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-
-    private void initializeValues(ScriptC_bug_char s) {
-        byte rand_sc1_0 = (byte)7;
-        byte[] rand_sc2_0 = new byte[2];
-        rand_sc2_0[0] = 11;
-        rand_sc2_0[1] = 21;
-        Log.i("bug_char", "Generated sc2_0 to " + Arrays.toString(rand_sc2_0));
-        byte rand_sc1_1 = (byte)10;
-        byte[] rand_sc2_1 = new byte[2];
-        rand_sc2_1[0] = 13;
-        rand_sc2_1[1] = 15;
-        Log.i("bug_char", "Generated sc2_1 to " + Arrays.toString(rand_sc2_1));
-
-        s.set_rand_sc1_0(rand_sc1_0);
-        s.set_rand_sc2_0(pack_b2(rand_sc2_0));
-        s.set_rand_sc1_1(rand_sc1_1);
-        s.set_rand_sc2_1(pack_b2(rand_sc2_1));
-        // Set results for min
-        s.set_min_rand_sc1_sc1(min(rand_sc1_0, rand_sc1_1));
-        byte[] min_rand_sc2_raw = min(rand_sc2_0, rand_sc2_1);
-        Log.i("bug_char", "Generating min_rand_sc2_sc2 to " +
-              Arrays.toString(min_rand_sc2_raw));
-        Byte2 min_rand_sc2 = pack_b2(min_rand_sc2_raw);
-        Log.i("bug_char", "Setting min_rand_sc2_sc2 to [" + min_rand_sc2.x +
-              ", " + min_rand_sc2.y + "]");
-        s.set_min_rand_sc2_sc2(min_rand_sc2);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_bug_char s = new ScriptC_bug_char(pRS, mRes,
-                R.raw.bug_char);
-        pRS.setMessageHandler(mRsMessage);
-        initializeValues(s);
-        s.invoke_bug_char_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_clamp.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_clamp.java
deleted file mode 100644
index 1f28abc..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_clamp.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_clamp extends UnitTest {
-    private Resources mRes;
-
-    protected UT_clamp(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Clamp (Full)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_clamp s = new ScriptC_clamp(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_clamp_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_clamp_relaxed.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_clamp_relaxed.java
deleted file mode 100644
index d880e68..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_clamp_relaxed.java
+++ /dev/null
@@ -1,41 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_clamp_relaxed extends UnitTest {
-    private Resources mRes;
-
-    protected UT_clamp_relaxed(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Clamp (Relaxed)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_clamp_relaxed s =
-                new ScriptC_clamp_relaxed(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_clamp_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_constant.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_constant.java
deleted file mode 100644
index 3085032..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_constant.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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_constant extends UnitTest {
-    private Resources mRes;
-
-    protected UT_constant(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Const", ctx);
-        mRes = res;
-    }
-
-    private void Assert(boolean b) {
-        if (!b) {
-            failTest();
-        }
-    }
-
-    public void run() {
-        Assert(ScriptC_constant.const_floatTest == 1.99f);
-        Assert(ScriptC_constant.const_doubleTest == 2.05);
-        Assert(ScriptC_constant.const_charTest == -8);
-        Assert(ScriptC_constant.const_shortTest == -16);
-        Assert(ScriptC_constant.const_intTest == -32);
-        Assert(ScriptC_constant.const_longTest == 17179869184l);
-        Assert(ScriptC_constant.const_longlongTest == 68719476736l);
-
-        Assert(ScriptC_constant.const_ucharTest == 8);
-        Assert(ScriptC_constant.const_ushortTest == 16);
-        Assert(ScriptC_constant.const_uintTest == 32);
-        Assert(ScriptC_constant.const_ulongTest == 4611686018427387904L);
-        Assert(ScriptC_constant.const_int64_tTest == -17179869184l);
-        Assert(ScriptC_constant.const_uint64_tTest == 117179869184l);
-
-        Assert(ScriptC_constant.const_boolTest == true);
-
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_convert.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_convert.java
deleted file mode 100644
index a7cb226..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_convert.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_convert extends UnitTest {
-    private Resources mRes;
-
-    protected UT_convert(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Convert", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_convert s = new ScriptC_convert(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_convert_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_convert_relaxed.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_convert_relaxed.java
deleted file mode 100644
index 269bcef..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_convert_relaxed.java
+++ /dev/null
@@ -1,41 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_convert_relaxed extends UnitTest {
-    private Resources mRes;
-
-    protected UT_convert_relaxed(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Convert (Relaxed)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_convert_relaxed s =
-                new ScriptC_convert_relaxed(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_convert_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_copy_test.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_copy_test.java
deleted file mode 100644
index f435dde..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_copy_test.java
+++ /dev/null
@@ -1,120 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class UT_copy_test extends UnitTest {
-    private Resources mRes;
-    boolean pass = true;
-
-    protected UT_copy_test(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Copy", ctx);
-        mRes = res;
-    }
-
-    void testFloat2(RenderScript rs, ScriptC_copy_test s) {
-        Allocation a1 = Allocation.createSized(rs, Element.F32_2(rs), 1024);
-        Allocation a2 = Allocation.createSized(rs, Element.F32_2(rs), 1024);
-
-        float[] f1 = new float[1024 * 2];
-        float[] f2 = new float[1024 * 2];
-        for (int ct=0; ct < f1.length; ct++) {
-            f1[ct] = (float)ct;
-        }
-        a1.copyFrom(f1);
-
-        s.forEach_copyFloat2(a1, a2);
-
-        a2.copyTo(f2);
-        for (int ct=0; ct < f1.length; ct++) {
-            if (f1[ct] != f2[ct]) {
-                failTest();
-                Log.v("RS Test", "Compare failed at " + ct + ", " + f1[ct] + ", " + f2[ct]);
-            }
-        }
-        a1.destroy();
-        a2.destroy();
-    }
-
-    void testFloat3(RenderScript rs, ScriptC_copy_test s) {
-        Allocation a1 = Allocation.createSized(rs, Element.F32_3(rs), 1024);
-        Allocation a2 = Allocation.createSized(rs, Element.F32_3(rs), 1024);
-
-        float[] f1 = new float[1024 * 4];
-        float[] f2 = new float[1024 * 4];
-        for (int ct=0; ct < f1.length; ct++) {
-            f1[ct] = (float)ct;
-        }
-        a1.copyFrom(f1);
-
-        s.forEach_copyFloat3(a1, a2);
-
-        a2.copyTo(f2);
-        for (int ct=0; ct < f1.length; ct++) {
-            if ((f1[ct] != f2[ct]) && ((ct&3) != 3)) {
-                failTest();
-                Log.v("RS Test", "Compare failed at " + ct + ", " + f1[ct] + ", " + f2[ct]);
-            }
-        }
-        a1.destroy();
-        a2.destroy();
-    }
-
-    void testFloat4(RenderScript rs, ScriptC_copy_test s) {
-        Allocation a1 = Allocation.createSized(rs, Element.F32_4(rs), 1024);
-        Allocation a2 = Allocation.createSized(rs, Element.F32_4(rs), 1024);
-
-        float[] f1 = new float[1024 * 4];
-        float[] f2 = new float[1024 * 4];
-        for (int ct=0; ct < f1.length; ct++) {
-            f1[ct] = (float)ct;
-        }
-        a1.copyFrom(f1);
-
-        s.forEach_copyFloat4(a1, a2);
-
-        a2.copyTo(f2);
-        for (int ct=0; ct < f1.length; ct++) {
-            if (f1[ct] != f2[ct]) {
-                failTest();
-                Log.v("RS Test", "Compare failed at " + ct + ", " + f1[ct] + ", " + f2[ct]);
-            }
-        }
-        a1.destroy();
-        a2.destroy();
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_copy_test s = new ScriptC_copy_test(pRS);
-        pRS.setMessageHandler(mRsMessage);
-
-        testFloat2(pRS, s);
-        testFloat3(pRS, s);
-        testFloat4(pRS, s);
-        s.invoke_sendResult(true);
-
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_element.java
deleted file mode 100644
index abfa44c..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_element.java
+++ /dev/null
@@ -1,121 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_element extends UnitTest {
-    private Resources mRes;
-
-    Element simpleElem;
-    Element complexElem;
-
-    final String subElemNames[] = {
-        "subElem0",
-        "subElem1",
-        "subElem2",
-        "arrayElem0",
-        "arrayElem1",
-        "subElem3",
-        "subElem4",
-        "subElem5",
-        "subElem6",
-        "subElem_7",
-    };
-
-    final int subElemArraySizes[] = {
-        1,
-        1,
-        1,
-        2,
-        5,
-        1,
-        1,
-        1,
-        1,
-        1,
-    };
-
-    final int subElemOffsets[] = {
-        0,
-        4,
-        8,
-        12,
-        20,
-        40,
-        44,
-        48,
-        64,
-        80,
-    };
-
-    protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Element", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_element s) {
-        simpleElem = Element.F32_3(RS);
-        complexElem = ScriptField_ComplexStruct.createElement(RS);
-        s.set_simpleElem(simpleElem);
-        s.set_complexElem(complexElem);
-
-        ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
-        s.bind_complexStruct(data);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_element s = new ScriptC_element(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_element_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    private void testJavaSide(RenderScript RS) {
-
-        int subElemCount = simpleElem.getSubElementCount();
-        _RS_ASSERT("subElemCount == 0", subElemCount == 0);
-
-        subElemCount = complexElem.getSubElementCount();
-        _RS_ASSERT("subElemCount == 10", subElemCount == 10);
-        _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
-                   complexElem.getBytesSize() == ScriptField_ComplexStruct.Item.sizeof);
-
-        for (int i = 0; i < subElemCount; i ++) {
-            _RS_ASSERT("complexElem.getSubElement(i) != null",
-                       complexElem.getSubElement(i) != null);
-            _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
-                       complexElem.getSubElementName(i).equals(subElemNames[i]));
-            _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
-                       complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
-            _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
-                       complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
-        }
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testScriptSide(pRS);
-        testJavaSide(pRS);
-        passTest();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
deleted file mode 100644
index fd18f93..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011-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.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_foreach extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_foreach(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_foreach s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aRaw(A);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_foreach s = new ScriptC_foreach(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_root(A);
-        s.invoke_verify_root();
-        s.forEach_foo(A, A);
-        s.invoke_verify_foo();
-        s.invoke_foreach_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
deleted file mode 100644
index 13fefe7..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_foreach_bounds.java
+++ /dev/null
@@ -1,63 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_foreach_bounds extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_foreach_bounds(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach (bounds)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_foreach_bounds s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aRaw(A);
-        s.set_s(s);
-        s.set_ain(A);
-        s.set_aout(A);
-        s.set_xStart(2);
-        s.set_xEnd(5);
-        s.set_yStart(3);
-        s.set_yEnd(6);
-        s.forEach_zero(A);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_foreach_bounds s = new ScriptC_foreach_bounds(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_foreach_bounds_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_fp_mad.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_fp_mad.java
deleted file mode 100644
index 960df24..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_fp_mad.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_fp_mad extends UnitTest {
-    private Resources mRes;
-
-    protected UT_fp_mad(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Fp_Mad", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_fp_mad s = new ScriptC_fp_mad(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_fp_mad_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_int4.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_int4.java
deleted file mode 100644
index 9592798..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_int4.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_int4 extends UnitTest {
-    private Resources mRes;
-
-    protected UT_int4(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "int4", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_int4 s = new ScriptC_int4(pRS, mRes, R.raw.int4);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_int4_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_kernel.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_kernel.java
deleted file mode 100644
index ec67665..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_kernel.java
+++ /dev/null
@@ -1,60 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class UT_kernel extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-    private Allocation B;
-
-    protected UT_kernel(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Kernels (pass-by-value)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_kernel s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        s.set_dimX(X);
-        typeBuilder.setX(X);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_ain(A);
-        B = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_aout(B);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_kernel s = new ScriptC_kernel(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_init_vars(A);
-        s.forEach_root(A, B);
-        s.invoke_verify_root();
-        s.invoke_kernel_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_kernel_struct.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_kernel_struct.java
deleted file mode 100644
index 07538ec..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_kernel_struct.java
+++ /dev/null
@@ -1,61 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-import android.util.Log;
-
-public class UT_kernel_struct extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-    private Allocation B;
-
-    protected UT_kernel_struct(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Kernels (struct pass-by-value)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_kernel_struct s) {
-        int X = 5;
-        s.set_dimX(X);
-        ScriptField_simpleStruct t;
-        t = new ScriptField_simpleStruct(RS, X);
-        s.bind_ain(t);
-        A = t.getAllocation();
-        t = new ScriptField_simpleStruct(RS, X);
-        s.bind_aout(t);
-        B = t.getAllocation();
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_kernel_struct s = new ScriptC_kernel_struct(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_init_vars(A);
-        s.forEach_root(A, B);
-        s.invoke_verify_root();
-        s.invoke_kernel_struct_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math.java
deleted file mode 100644
index 055c454..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_math extends UnitTest {
-    private Resources mRes;
-
-    protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math s = new ScriptC_math(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_math_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math_agree.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math_agree.java
deleted file mode 100644
index a7e7429..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math_agree.java
+++ /dev/null
@@ -1,527 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-import android.util.Log;
-import java.util.Arrays;
-import java.util.Random;
-
-public class UT_math_agree extends UnitTest {
-    private Resources mRes;
-    private Random rand;
-
-    protected UT_math_agree(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math Agreement", ctx);
-        mRes = res;
-        rand = new Random();
-    }
-
-    // packing functions
-    private Float2 pack_f2(float[] val) {
-        assert val.length == 2;
-        return new Float2(val[0], val[1]);
-    }
-    private Float3 pack_f3(float[] val) {
-        assert val.length == 3;
-        return new Float3(val[0], val[1], val[2]);
-    }
-    private Float4 pack_f4(float[] val) {
-        assert val.length == 4;
-        return new Float4(val[0], val[1], val[2], val[3]);
-    }
-    private Byte2 pack_b2(byte[] val) {
-        assert val.length == 2;
-        return new Byte2(val[0], val[1]);
-    }
-    private Byte3 pack_b3(byte[] val) {
-        assert val.length == 3;
-        return new Byte3(val[0], val[1], val[2]);
-    }
-    private Byte4 pack_b4(byte[] val) {
-        assert val.length == 4;
-        return new Byte4(val[0], val[1], val[2], val[3]);
-    }
-    private Short2 pack_s2(short[] val) {
-        assert val.length == 2;
-        return new Short2(val[0], val[1]);
-    }
-    private Short3 pack_s3(short[] val) {
-        assert val.length == 3;
-        return new Short3(val[0], val[1], val[2]);
-    }
-    private Short4 pack_s4(short[] val) {
-        assert val.length == 4;
-        return new Short4(val[0], val[1], val[2], val[3]);
-    }
-    private Int2 pack_i2(int[] val) {
-        assert val.length == 2;
-        return new Int2(val[0], val[1]);
-    }
-    private Int3 pack_i3(int[] val) {
-        assert val.length == 3;
-        return new Int3(val[0], val[1], val[2]);
-    }
-    private Int4 pack_i4(int[] val) {
-        assert val.length == 4;
-        return new Int4(val[0], val[1], val[2], val[3]);
-    }
-    private Long2 pack_l2(long[] val) {
-        assert val.length == 2;
-        return new Long2(val[0], val[1]);
-    }
-    private Long3 pack_l3(long[] val) {
-        assert val.length == 3;
-        return new Long3(val[0], val[1], val[2]);
-    }
-    private Long4 pack_l4(long[] val) {
-        assert val.length == 4;
-        return new Long4(val[0], val[1], val[2], val[3]);
-    }
-
-    // random vector generation functions
-    private float[] randvec_float(int dim) {
-        float[] fv = new float[dim];
-        for (int i = 0; i < dim; ++i)
-            fv[i] = rand.nextFloat();
-        return fv;
-    }
-    private byte[] randvec_char(int dim) {
-        byte[] cv = new byte[dim];
-        rand.nextBytes(cv);
-        return cv;
-    }
-    private short[] randvec_uchar(int dim) {
-       short[] ucv = new short[dim];
-       for (int i = 0; i < dim; ++i)
-           ucv[i] = (short)rand.nextInt(0x1 << 8);
-       return ucv;
-    }
-    private short[] randvec_short(int dim) {
-        short[] sv = new short[dim];
-        for (int i = 0; i < dim; ++i)
-            sv[i] = (short)rand.nextInt(0x1 << 16);
-        return sv;
-    }
-    private int[] randvec_ushort(int dim) {
-        int[] usv = new int[dim];
-        for (int i = 0; i < dim; ++i)
-            usv[i] = rand.nextInt(0x1 << 16);
-        return usv;
-    }
-    private int[] randvec_int(int dim) {
-        int[] iv = new int[dim];
-        for (int i = 0; i < dim; ++i)
-            iv[i] = rand.nextInt();
-        return iv;
-    }
-    private long[] randvec_uint(int dim) {
-        long[] uiv = new long[dim];
-        for (int i = 0; i < dim; ++i)
-            uiv[i] = (long)rand.nextInt() - (long)Integer.MIN_VALUE;
-        return uiv;
-    }
-    private long[] randvec_long(int dim) {
-        long[] lv = new long[dim];
-        for (int i = 0; i < dim; ++i)
-            lv[i] = rand.nextLong();
-        return lv;
-    }
-    // TODO:  unsigned long generator
-
-    // min reference functions
-    private float min(float v1, float v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private float[] min(float[] v1, float[] v2) {
-        assert v1.length == v2.length;
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private byte min(byte v1, byte v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private byte[] min(byte[] v1, byte[] v2) {
-        assert v1.length == v2.length;
-        byte[] rv = new byte[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private short min(short v1, short v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private short[] min(short[] v1, short[] v2) {
-        assert v1.length == v2.length;
-        short[] rv = new short[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private int min(int v1, int v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private int[] min(int[] v1, int[] v2) {
-        assert v1.length == v2.length;
-        int[] rv = new int[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private long min(long v1, long v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private long[] min(long[] v1, long[] v2) {
-        assert v1.length == v2.length;
-        long[] rv = new long[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    // TODO:  unsigned long version of min
-
-    // max reference functions
-    private float max(float v1, float v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private float[] max(float[] v1, float[] v2) {
-        assert v1.length == v2.length;
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private byte max(byte v1, byte v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private byte[] max(byte[] v1, byte[] v2) {
-        assert v1.length == v2.length;
-        byte[] rv = new byte[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private short max(short v1, short v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private short[] max(short[] v1, short[] v2) {
-        assert v1.length == v2.length;
-        short[] rv = new short[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private int max(int v1, int v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private int[] max(int[] v1, int[] v2) {
-        assert v1.length == v2.length;
-        int[] rv = new int[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private long max(long v1, long v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private long[] max(long[] v1, long[] v2) {
-        assert v1.length == v2.length;
-        long[] rv = new long[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    // TODO:  unsigned long version of max
-
-    // fmin reference functions
-    private float fmin(float v1, float v2) {
-        return min(v1, v2);
-    }
-    private float[] fmin(float[] v1, float[] v2) {
-        return min(v1, v2);
-    }
-    private float[] fmin(float[] v1, float v2) {
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2);
-        return rv;
-    }
-
-    // fmax reference functions
-    private float fmax(float v1, float v2) {
-        return max(v1, v2);
-    }
-    private float[] fmax(float[] v1, float[] v2) {
-        return max(v1, v2);
-    }
-    private float[] fmax(float[] v1, float v2) {
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2);
-        return rv;
-    }
-
-    private void initializeValues(ScriptC_math_agree s) {
-        float x = rand.nextFloat();
-        float y = rand.nextFloat();
-
-        s.set_x(x);
-        s.set_y(y);
-        s.set_result_add(x + y);
-        s.set_result_sub(x - y);
-        s.set_result_mul(x * y);
-        s.set_result_div(x / y);
-
-        // Generate random vectors of all types
-        float rand_f1_0 = rand.nextFloat();
-        float[] rand_f2_0 = randvec_float(2);
-        float[] rand_f3_0 = randvec_float(3);
-        float[] rand_f4_0 = randvec_float(4);
-        float rand_f1_1 = rand.nextFloat();
-        float[] rand_f2_1 = randvec_float(2);
-        float[] rand_f3_1 = randvec_float(3);
-        float[] rand_f4_1 = randvec_float(4);
-        short rand_uc1_0 = (short)rand.nextInt(0x1 << 8);
-        short[] rand_uc2_0 = randvec_uchar(2);
-        short[] rand_uc3_0 = randvec_uchar(3);
-        short[] rand_uc4_0 = randvec_uchar(4);
-        short rand_uc1_1 = (short)rand.nextInt(0x1 << 8);
-        short[] rand_uc2_1 = randvec_uchar(2);
-        short[] rand_uc3_1 = randvec_uchar(3);
-        short[] rand_uc4_1 = randvec_uchar(4);
-        short rand_ss1_0 = (short)rand.nextInt(0x1 << 16);
-        short[] rand_ss2_0 = randvec_short(2);
-        short[] rand_ss3_0 = randvec_short(3);
-        short[] rand_ss4_0 = randvec_short(4);
-        short rand_ss1_1 = (short)rand.nextInt(0x1 << 16);
-        short[] rand_ss2_1 = randvec_short(2);
-        short[] rand_ss3_1 = randvec_short(3);
-        short[] rand_ss4_1 = randvec_short(4);
-        int rand_us1_0 = rand.nextInt(0x1 << 16);
-        int[] rand_us2_0 = randvec_ushort(2);
-        int[] rand_us3_0 = randvec_ushort(3);
-        int[] rand_us4_0 = randvec_ushort(4);
-        int rand_us1_1 = rand.nextInt(0x1 << 16);
-        int[] rand_us2_1 = randvec_ushort(2);
-        int[] rand_us3_1 = randvec_ushort(3);
-        int[] rand_us4_1 = randvec_ushort(4);
-        int rand_si1_0 = rand.nextInt();
-        int[] rand_si2_0 = randvec_int(2);
-        int[] rand_si3_0 = randvec_int(3);
-        int[] rand_si4_0 = randvec_int(4);
-        int rand_si1_1 = rand.nextInt();
-        int[] rand_si2_1 = randvec_int(2);
-        int[] rand_si3_1 = randvec_int(3);
-        int[] rand_si4_1 = randvec_int(4);
-        long rand_ui1_0 = (long)rand.nextInt() - (long)Integer.MIN_VALUE;
-        long[] rand_ui2_0 = randvec_uint(2);
-        long[] rand_ui3_0 = randvec_uint(3);
-        long[] rand_ui4_0 = randvec_uint(4);
-        long rand_ui1_1 = (long)rand.nextInt() - (long)Integer.MIN_VALUE;
-        long[] rand_ui2_1 = randvec_uint(2);
-        long[] rand_ui3_1 = randvec_uint(3);
-        long[] rand_ui4_1 = randvec_uint(4);
-        long rand_sl1_0 = rand.nextLong();
-        long[] rand_sl2_0 = randvec_long(2);
-        long[] rand_sl3_0 = randvec_long(3);
-        long[] rand_sl4_0 = randvec_long(4);
-        long rand_sl1_1 = rand.nextLong();
-        long[] rand_sl2_1 = randvec_long(2);
-        long[] rand_sl3_1 = randvec_long(3);
-        long[] rand_sl4_1 = randvec_long(4);
-        byte rand_sc1_0 = (byte)rand.nextInt(0x1 << 8);
-        byte[] rand_sc2_0 = randvec_char(2);
-        byte[] rand_sc3_0 = randvec_char(3);
-        byte[] rand_sc4_0 = randvec_char(4);
-        byte rand_sc1_1 = (byte)rand.nextInt(0x1 << 8);
-        byte[] rand_sc2_1 = randvec_char(2);
-        byte[] rand_sc3_1 = randvec_char(3);
-        byte[] rand_sc4_1 = randvec_char(4);
-        // TODO:  generate unsigned long vectors
-
-        // Set random vectors in renderscript code
-        s.set_rand_f1_0(rand_f1_0);
-        s.set_rand_f2_0(pack_f2(rand_f2_0));
-        s.set_rand_f3_0(pack_f3(rand_f3_0));
-        s.set_rand_f4_0(pack_f4(rand_f4_0));
-        s.set_rand_f1_1(rand_f1_1);
-        s.set_rand_f2_1(pack_f2(rand_f2_1));
-        s.set_rand_f3_1(pack_f3(rand_f3_1));
-        s.set_rand_f4_1(pack_f4(rand_f4_1));
-        s.set_rand_uc1_1(rand_uc1_1);
-        s.set_rand_uc2_1(pack_s2(rand_uc2_1));
-        s.set_rand_uc3_1(pack_s3(rand_uc3_1));
-        s.set_rand_uc4_1(pack_s4(rand_uc4_1));
-        s.set_rand_ss1_0(rand_ss1_0);
-        s.set_rand_ss2_0(pack_s2(rand_ss2_0));
-        s.set_rand_ss3_0(pack_s3(rand_ss3_0));
-        s.set_rand_ss4_0(pack_s4(rand_ss4_0));
-        s.set_rand_ss1_1(rand_ss1_1);
-        s.set_rand_ss2_1(pack_s2(rand_ss2_1));
-        s.set_rand_ss3_1(pack_s3(rand_ss3_1));
-        s.set_rand_ss4_1(pack_s4(rand_ss4_1));
-        s.set_rand_us1_0(rand_us1_0);
-        s.set_rand_us2_0(pack_i2(rand_us2_0));
-        s.set_rand_us3_0(pack_i3(rand_us3_0));
-        s.set_rand_us4_0(pack_i4(rand_us4_0));
-        s.set_rand_us1_1(rand_us1_1);
-        s.set_rand_us2_1(pack_i2(rand_us2_1));
-        s.set_rand_us3_1(pack_i3(rand_us3_1));
-        s.set_rand_us4_1(pack_i4(rand_us4_1));
-        s.set_rand_si1_0(rand_si1_0);
-        s.set_rand_si2_0(pack_i2(rand_si2_0));
-        s.set_rand_si3_0(pack_i3(rand_si3_0));
-        s.set_rand_si4_0(pack_i4(rand_si4_0));
-        s.set_rand_si1_1(rand_si1_1);
-        s.set_rand_si2_1(pack_i2(rand_si2_1));
-        s.set_rand_si3_1(pack_i3(rand_si3_1));
-        s.set_rand_si4_1(pack_i4(rand_si4_1));
-        s.set_rand_ui1_0(rand_ui1_0);
-        s.set_rand_ui2_0(pack_l2(rand_ui2_0));
-        s.set_rand_ui3_0(pack_l3(rand_ui3_0));
-        s.set_rand_ui4_0(pack_l4(rand_ui4_0));
-        s.set_rand_ui1_1(rand_ui1_1);
-        s.set_rand_ui2_1(pack_l2(rand_ui2_1));
-        s.set_rand_ui3_1(pack_l3(rand_ui3_1));
-        s.set_rand_ui4_1(pack_l4(rand_ui4_1));
-        s.set_rand_sl1_0(rand_sl1_0);
-        s.set_rand_sl2_0(pack_l2(rand_sl2_0));
-        s.set_rand_sl3_0(pack_l3(rand_sl3_0));
-        s.set_rand_sl4_0(pack_l4(rand_sl4_0));
-        s.set_rand_sl1_1(rand_sl1_1);
-        s.set_rand_sl2_1(pack_l2(rand_sl2_1));
-        s.set_rand_sl3_1(pack_l3(rand_sl3_1));
-        s.set_rand_sl4_1(pack_l4(rand_sl4_1));
-        s.set_rand_uc1_0(rand_uc1_0);
-        s.set_rand_uc2_0(pack_s2(rand_uc2_0));
-        s.set_rand_uc3_0(pack_s3(rand_uc3_0));
-        s.set_rand_uc4_0(pack_s4(rand_uc4_0));
-        s.set_rand_sc1_0(rand_sc1_0);
-        s.set_rand_sc2_0(pack_b2(rand_sc2_0));
-        s.set_rand_sc3_0(pack_b3(rand_sc3_0));
-        s.set_rand_sc4_0(pack_b4(rand_sc4_0));
-        s.set_rand_sc1_1(rand_sc1_1);
-        s.set_rand_sc2_1(pack_b2(rand_sc2_1));
-        s.set_rand_sc3_1(pack_b3(rand_sc3_1));
-        s.set_rand_sc4_1(pack_b4(rand_sc4_1));
-        // TODO:  set unsigned long vectors
-
-        // Set results for min
-        s.set_min_rand_f1_f1(min(rand_f1_0, rand_f1_1));
-        s.set_min_rand_f2_f2(pack_f2(min(rand_f2_0, rand_f2_1)));
-        s.set_min_rand_f3_f3(pack_f3(min(rand_f3_0, rand_f3_1)));
-        s.set_min_rand_f4_f4(pack_f4(min(rand_f4_0, rand_f4_1)));
-        s.set_min_rand_uc1_uc1(min(rand_uc1_0, rand_uc1_1));
-        s.set_min_rand_uc2_uc2(pack_s2(min(rand_uc2_0, rand_uc2_1)));
-        s.set_min_rand_uc3_uc3(pack_s3(min(rand_uc3_0, rand_uc3_1)));
-        s.set_min_rand_uc4_uc4(pack_s4(min(rand_uc4_0, rand_uc4_1)));
-        s.set_min_rand_ss1_ss1(min(rand_ss1_0, rand_ss1_1));
-        s.set_min_rand_ss2_ss2(pack_s2(min(rand_ss2_0, rand_ss2_1)));
-        s.set_min_rand_ss3_ss3(pack_s3(min(rand_ss3_0, rand_ss3_1)));
-        s.set_min_rand_ss4_ss4(pack_s4(min(rand_ss4_0, rand_ss4_1)));
-        s.set_min_rand_us1_us1(min(rand_us1_0, rand_us1_1));
-        s.set_min_rand_us2_us2(pack_i2(min(rand_us2_0, rand_us2_1)));
-        s.set_min_rand_us3_us3(pack_i3(min(rand_us3_0, rand_us3_1)));
-        s.set_min_rand_us4_us4(pack_i4(min(rand_us4_0, rand_us4_1)));
-        s.set_min_rand_si1_si1(min(rand_si1_0, rand_si1_1));
-        s.set_min_rand_si2_si2(pack_i2(min(rand_si2_0, rand_si2_1)));
-        s.set_min_rand_si3_si3(pack_i3(min(rand_si3_0, rand_si3_1)));
-        s.set_min_rand_si4_si4(pack_i4(min(rand_si4_0, rand_si4_1)));
-        s.set_min_rand_ui1_ui1(min(rand_ui1_0, rand_ui1_1));
-        s.set_min_rand_ui2_ui2(pack_l2(min(rand_ui2_0, rand_ui2_1)));
-        s.set_min_rand_ui3_ui3(pack_l3(min(rand_ui3_0, rand_ui3_1)));
-        s.set_min_rand_ui4_ui4(pack_l4(min(rand_ui4_0, rand_ui4_1)));
-        s.set_min_rand_sl1_sl1(min(rand_sl1_0, rand_sl1_1));
-        s.set_min_rand_sl2_sl2(pack_l2(min(rand_sl2_0, rand_sl2_1)));
-        s.set_min_rand_sl3_sl3(pack_l3(min(rand_sl3_0, rand_sl3_1)));
-        s.set_min_rand_sl4_sl4(pack_l4(min(rand_sl4_0, rand_sl4_1)));
-        s.set_min_rand_sc1_sc1(min(rand_sc1_0, rand_sc1_1));
-        s.set_min_rand_sc2_sc2(pack_b2(min(rand_sc2_0, rand_sc2_1)));
-        s.set_min_rand_sc3_sc3(pack_b3(min(rand_sc3_0, rand_sc3_1)));
-        s.set_min_rand_sc4_sc4(pack_b4(min(rand_sc4_0, rand_sc4_1)));
-        // TODO:  set results for unsigned long min
-
-        // Set results for max
-        s.set_max_rand_f1_f1(max(rand_f1_0, rand_f1_1));
-        s.set_max_rand_f2_f2(pack_f2(max(rand_f2_0, rand_f2_1)));
-        s.set_max_rand_f3_f3(pack_f3(max(rand_f3_0, rand_f3_1)));
-        s.set_max_rand_f4_f4(pack_f4(max(rand_f4_0, rand_f4_1)));
-        s.set_max_rand_uc1_uc1(max(rand_uc1_0, rand_uc1_1));
-        s.set_max_rand_uc2_uc2(pack_s2(max(rand_uc2_0, rand_uc2_1)));
-        s.set_max_rand_uc3_uc3(pack_s3(max(rand_uc3_0, rand_uc3_1)));
-        s.set_max_rand_uc4_uc4(pack_s4(max(rand_uc4_0, rand_uc4_1)));
-        s.set_max_rand_ss1_ss1(max(rand_ss1_0, rand_ss1_1));
-        s.set_max_rand_ss2_ss2(pack_s2(max(rand_ss2_0, rand_ss2_1)));
-        s.set_max_rand_ss3_ss3(pack_s3(max(rand_ss3_0, rand_ss3_1)));
-        s.set_max_rand_ss4_ss4(pack_s4(max(rand_ss4_0, rand_ss4_1)));
-        s.set_max_rand_us1_us1(max(rand_us1_0, rand_us1_1));
-        s.set_max_rand_us2_us2(pack_i2(max(rand_us2_0, rand_us2_1)));
-        s.set_max_rand_us3_us3(pack_i3(max(rand_us3_0, rand_us3_1)));
-        s.set_max_rand_us4_us4(pack_i4(max(rand_us4_0, rand_us4_1)));
-        s.set_max_rand_si1_si1(max(rand_si1_0, rand_si1_1));
-        s.set_max_rand_si2_si2(pack_i2(max(rand_si2_0, rand_si2_1)));
-        s.set_max_rand_si3_si3(pack_i3(max(rand_si3_0, rand_si3_1)));
-        s.set_max_rand_si4_si4(pack_i4(max(rand_si4_0, rand_si4_1)));
-        s.set_max_rand_ui1_ui1(max(rand_ui1_0, rand_ui1_1));
-        s.set_max_rand_ui2_ui2(pack_l2(max(rand_ui2_0, rand_ui2_1)));
-        s.set_max_rand_ui3_ui3(pack_l3(max(rand_ui3_0, rand_ui3_1)));
-        s.set_max_rand_ui4_ui4(pack_l4(max(rand_ui4_0, rand_ui4_1)));
-        s.set_max_rand_sl1_sl1(max(rand_sl1_0, rand_sl1_1));
-        s.set_max_rand_sl2_sl2(pack_l2(max(rand_sl2_0, rand_sl2_1)));
-        s.set_max_rand_sl3_sl3(pack_l3(max(rand_sl3_0, rand_sl3_1)));
-        s.set_max_rand_sl4_sl4(pack_l4(max(rand_sl4_0, rand_sl4_1)));
-        s.set_max_rand_sc1_sc1(max(rand_sc1_0, rand_sc1_1));
-        s.set_max_rand_sc2_sc2(pack_b2(max(rand_sc2_0, rand_sc2_1)));
-        s.set_max_rand_sc3_sc3(pack_b3(max(rand_sc3_0, rand_sc3_1)));
-        s.set_max_rand_sc4_sc4(pack_b4(max(rand_sc4_0, rand_sc4_1)));
-
-        // TODO:  set results for unsigned long max
-
-        // Set results for fmin
-        s.set_fmin_rand_f1_f1(fmin(rand_f1_0, rand_f1_1));
-        s.set_fmin_rand_f2_f2(pack_f2(fmin(rand_f2_0, rand_f2_1)));
-        s.set_fmin_rand_f3_f3(pack_f3(fmin(rand_f3_0, rand_f3_1)));
-        s.set_fmin_rand_f4_f4(pack_f4(fmin(rand_f4_0, rand_f4_1)));
-        s.set_fmin_rand_f2_f1(pack_f2(fmin(rand_f2_0, rand_f1_1)));
-        s.set_fmin_rand_f3_f1(pack_f3(fmin(rand_f3_0, rand_f1_1)));
-        s.set_fmin_rand_f4_f1(pack_f4(fmin(rand_f4_0, rand_f1_1)));
-
-        // Set results for fmax
-        s.set_fmax_rand_f1_f1(fmax(rand_f1_0, rand_f1_1));
-        s.set_fmax_rand_f2_f2(pack_f2(fmax(rand_f2_0, rand_f2_1)));
-        s.set_fmax_rand_f3_f3(pack_f3(fmax(rand_f3_0, rand_f3_1)));
-        s.set_fmax_rand_f4_f4(pack_f4(fmax(rand_f4_0, rand_f4_1)));
-        s.set_fmax_rand_f2_f1(pack_f2(fmax(rand_f2_0, rand_f1_1)));
-        s.set_fmax_rand_f3_f1(pack_f3(fmax(rand_f3_0, rand_f1_1)));
-        s.set_fmax_rand_f4_f1(pack_f4(fmax(rand_f4_0, rand_f1_1)));
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math_agree s = new ScriptC_math_agree(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeValues(s);
-        s.invoke_math_agree_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math_conformance.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math_conformance.java
deleted file mode 100644
index 384cd13..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_math_conformance.java
+++ /dev/null
@@ -1,42 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_math_conformance extends UnitTest {
-    private Resources mRes;
-
-    protected UT_math_conformance(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math Conformance", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math_conformance s =
-                new ScriptC_math_conformance(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_math_conformance_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_min.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_min.java
deleted file mode 100644
index cea9fe5..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_min.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_min extends UnitTest {
-    private Resources mRes;
-
-    protected UT_min(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Min (relaxed)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_min s = new ScriptC_min(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_min_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
deleted file mode 100644
index 606af4d..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_noroot.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011-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.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_noroot extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_noroot(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach (no root)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_noroot s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aRaw(A);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_noroot s = new ScriptC_noroot(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_foo(A, A);
-        s.invoke_verify_foo();
-        s.invoke_noroot_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_primitives.java
deleted file mode 100644
index 3c663a8..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_primitives.java
+++ /dev/null
@@ -1,103 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_primitives extends UnitTest {
-    private Resources mRes;
-
-    protected UT_primitives(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Primitives", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_primitives s) {
-        float pF = s.get_floatTest();
-        if (pF != 1.99f) {
-            return false;
-        }
-        s.set_floatTest(2.99f);
-
-        double pD = s.get_doubleTest();
-        if (pD != 2.05) {
-            return false;
-        }
-        s.set_doubleTest(3.05);
-
-        byte pC = s.get_charTest();
-        if (pC != -8) {
-            return false;
-        }
-        s.set_charTest((byte)-16);
-
-        short pS = s.get_shortTest();
-        if (pS != -16) {
-            return false;
-        }
-        s.set_shortTest((short)-32);
-
-        int pI = s.get_intTest();
-        if (pI != -32) {
-            return false;
-        }
-        s.set_intTest(-64);
-
-        long pL = s.get_longTest();
-        if (pL != 17179869184l) {
-            return false;
-        }
-        s.set_longTest(17179869185l);
-
-        long puL = s.get_ulongTest();
-        if (puL != 4611686018427387904L) {
-            return false;
-        }
-        s.set_ulongTest(4611686018427387903L);
-
-
-        long pLL = s.get_longlongTest();
-        if (pLL != 68719476736L) {
-            return false;
-        }
-        s.set_longlongTest(68719476735L);
-
-        long pu64 = s.get_uint64_tTest();
-        if (pu64 != 117179869184l) {
-            return false;
-        }
-        s.set_uint64_tTest(117179869185l);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_primitives s = new ScriptC_primitives(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            failTest();
-        } else {
-            s.invoke_primitives_test(0, 0);
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_refcount.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_refcount.java
deleted file mode 100644
index e6317d5..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_refcount.java
+++ /dev/null
@@ -1,50 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_refcount extends UnitTest {
-    private Resources mRes;
-
-    protected UT_refcount(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Refcount", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_refcount s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 500;
-        int Y = 700;
-        typeBuilder.setX(X).setY(Y);
-        Allocation A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_globalA(A);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        pRS.setMessageHandler(mRsMessage);
-        ScriptC_refcount s = new ScriptC_refcount(pRS);
-        initializeGlobals(pRS, s);
-        s.invoke_refcount_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rsdebug.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rsdebug.java
deleted file mode 100644
index 740180e..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rsdebug.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_rsdebug extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rsdebug(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsDebug", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rsdebug s = new ScriptC_rsdebug(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rsdebug(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rstime.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rstime.java
deleted file mode 100644
index 86e35a8..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rstime.java
+++ /dev/null
@@ -1,41 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_rstime extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTime", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstime s = new ScriptC_rstime(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.setTimeZone("America/Los_Angeles");
-        s.invoke_test_rstime(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rstypes.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rstypes.java
deleted file mode 100644
index 3245eca..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_rstypes.java
+++ /dev/null
@@ -1,40 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_rstypes extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstypes(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTypes", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstypes s = new ScriptC_rstypes(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rstypes(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_sampler.java
deleted file mode 100644
index d8d5a78..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_sampler.java
+++ /dev/null
@@ -1,148 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_sampler extends UnitTest {
-    private Resources mRes;
-
-    Sampler minification;
-    Sampler magnification;
-    Sampler wrapS;
-    Sampler wrapT;
-    Sampler anisotropy;
-
-    protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Sampler", ctx);
-        mRes = res;
-    }
-
-    private Sampler.Builder getDefaultBuilder(RenderScript RS) {
-        Sampler.Builder b = new Sampler.Builder(RS);
-        b.setMinification(Sampler.Value.NEAREST);
-        b.setMagnification(Sampler.Value.NEAREST);
-        b.setWrapS(Sampler.Value.CLAMP);
-        b.setWrapT(Sampler.Value.CLAMP);
-        b.setAnisotropy(1.0f);
-        return b;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
-        Sampler.Builder b = getDefaultBuilder(RS);
-        b.setMinification(Sampler.Value.LINEAR_MIP_LINEAR);
-        minification = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setMagnification(Sampler.Value.LINEAR);
-        magnification = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setWrapS(Sampler.Value.WRAP);
-        wrapS = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setWrapT(Sampler.Value.WRAP);
-        wrapT = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setAnisotropy(8.0f);
-        anisotropy = b.create();
-
-        s.set_minification(minification);
-        s.set_magnification(magnification);
-        s.set_wrapS(wrapS);
-        s.set_wrapT(wrapT);
-        s.set_anisotropy(anisotropy);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_sampler s = new ScriptC_sampler(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_sampler_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    private void testJavaSide(RenderScript RS) {
-        _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST",
-                    minification.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR",
-                    minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR);
-        _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP",
-                    minification.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP",
-                    minification.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("minification.getAnisotropy() == 1.0f",
-                    minification.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR",
-                    magnification.getMagnification() == Sampler.Value.LINEAR);
-        _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST",
-                    magnification.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP",
-                    magnification.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP",
-                    magnification.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("magnification.getAnisotropy() == 1.0f",
-                    magnification.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST",
-                    wrapS.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST",
-                    wrapS.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP",
-                    wrapS.getWrapS() == Sampler.Value.WRAP);
-        _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP",
-                    wrapS.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("wrapS.getAnisotropy() == 1.0f",
-                    wrapS.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST",
-                    wrapT.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST",
-                    wrapT.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP",
-                    wrapT.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP",
-                    wrapT.getWrapT() == Sampler.Value.WRAP);
-        _RS_ASSERT("wrapT.getAnisotropy() == 1.0f",
-                    wrapT.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST",
-                    anisotropy.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST",
-                    anisotropy.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP",
-                    anisotropy.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP",
-                    anisotropy.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f",
-                    anisotropy.getAnisotropy() == 8.0f);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testScriptSide(pRS);
-        testJavaSide(pRS);
-        passTest();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_struct.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_struct.java
deleted file mode 100644
index 43bbaf7..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_struct.java
+++ /dev/null
@@ -1,55 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_struct extends UnitTest {
-    private Resources mRes;
-
-    protected UT_struct(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Struct", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_struct s = new ScriptC_struct(pRS);
-        pRS.setMessageHandler(mRsMessage);
-
-        ScriptField_Point2 p = new ScriptField_Point2(pRS, 1);
-        ScriptField_Point2.Item i = new ScriptField_Point2.Item();
-        int val = 100;
-        i.x = val;
-        i.y = val;
-        p.set(i, 0, true);
-        s.bind_point2(p);
-        s.invoke_struct_test(val);
-        pRS.finish();
-        waitForMessage();
-
-        val = 200;
-        p.set_x(0, val, true);
-        p.set_y(0, val, true);
-        s.invoke_struct_test(val);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_unsigned.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_unsigned.java
deleted file mode 100644
index 0e16240..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_unsigned.java
+++ /dev/null
@@ -1,60 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_unsigned extends UnitTest {
-    private Resources mRes;
-
-    protected UT_unsigned(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Unsigned", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_unsigned s) {
-        short pUC = s.get_uc();
-        if (pUC != 5) {
-            return false;
-        }
-        s.set_uc((short)129);
-
-        long pUI = s.get_ui();
-        if (pUI != 37) {
-            return false;
-        }
-        s.set_ui(0x7fffffff);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_unsigned s = new ScriptC_unsigned(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            failTest();
-        } else {
-            s.invoke_unsigned_test();
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_vector.java
deleted file mode 100644
index 6ba822e..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UT_vector.java
+++ /dev/null
@@ -1,318 +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 com.android.rs.test_compat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.support.v8.renderscript.*;
-
-public class UT_vector extends UnitTest {
-    private Resources mRes;
-
-    protected UT_vector(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Vector", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_vector s) {
-        Float2 F2 = s.get_f2();
-        if (F2.x != 1.0f || F2.y != 2.0f) {
-            return false;
-        }
-        F2.x = 2.99f;
-        F2.y = 3.99f;
-        s.set_f2(F2);
-
-        Float3 F3 = s.get_f3();
-        if (F3.x != 1.0f || F3.y != 2.0f || F3.z != 3.0f) {
-            return false;
-        }
-        F3.x = 2.99f;
-        F3.y = 3.99f;
-        F3.z = 4.99f;
-        s.set_f3(F3);
-
-        Float4 F4 = s.get_f4();
-        if (F4.x != 1.0f || F4.y != 2.0f || F4.z != 3.0f || F4.w != 4.0f) {
-            return false;
-        }
-        F4.x = 2.99f;
-        F4.y = 3.99f;
-        F4.z = 4.99f;
-        F4.w = 5.99f;
-        s.set_f4(F4);
-
-        Double2 D2 = s.get_d2();
-        if (D2.x != 1.0 || D2.y != 2.0) {
-            return false;
-        }
-        D2.x = 2.99;
-        D2.y = 3.99;
-        s.set_d2(D2);
-
-        Double3 D3 = s.get_d3();
-        if (D3.x != 1.0 || D3.y != 2.0 || D3.z != 3.0) {
-            return false;
-        }
-        D3.x = 2.99;
-        D3.y = 3.99;
-        D3.z = 4.99;
-        s.set_d3(D3);
-
-        Double4 D4 = s.get_d4();
-        if (D4.x != 1.0 || D4.y != 2.0 || D4.z != 3.0 || D4.w != 4.0) {
-            return false;
-        }
-        D4.x = 2.99;
-        D4.y = 3.99;
-        D4.z = 4.99;
-        D4.w = 5.99;
-        s.set_d4(D4);
-
-        Byte2 B2 = s.get_i8_2();
-        if (B2.x != 1 || B2.y != 2) {
-            return false;
-        }
-        B2.x = 2;
-        B2.y = 3;
-        s.set_i8_2(B2);
-
-        Byte3 B3 = s.get_i8_3();
-        if (B3.x != 1 || B3.y != 2 || B3.z != 3) {
-            return false;
-        }
-        B3.x = 2;
-        B3.y = 3;
-        B3.z = 4;
-        s.set_i8_3(B3);
-
-        Byte4 B4 = s.get_i8_4();
-        if (B4.x != 1 || B4.y != 2 || B4.z != 3 || B4.w != 4) {
-            return false;
-        }
-        B4.x = 2;
-        B4.y = 3;
-        B4.z = 4;
-        B4.w = 5;
-        s.set_i8_4(B4);
-
-        Short2 S2 = s.get_u8_2();
-        if (S2.x != 1 || S2.y != 2) {
-            return false;
-        }
-        S2.x = 2;
-        S2.y = 3;
-        s.set_u8_2(S2);
-
-        Short3 S3 = s.get_u8_3();
-        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
-            return false;
-        }
-        S3.x = 2;
-        S3.y = 3;
-        S3.z = 4;
-        s.set_u8_3(S3);
-
-        Short4 S4 = s.get_u8_4();
-        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
-            return false;
-        }
-        S4.x = 2;
-        S4.y = 3;
-        S4.z = 4;
-        S4.w = 5;
-        s.set_u8_4(S4);
-
-        S2 = s.get_i16_2();
-        if (S2.x != 1 || S2.y != 2) {
-            return false;
-        }
-        S2.x = 2;
-        S2.y = 3;
-        s.set_i16_2(S2);
-
-        S3 = s.get_i16_3();
-        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
-            return false;
-        }
-        S3.x = 2;
-        S3.y = 3;
-        S3.z = 4;
-        s.set_i16_3(S3);
-
-        S4 = s.get_i16_4();
-        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
-            return false;
-        }
-        S4.x = 2;
-        S4.y = 3;
-        S4.z = 4;
-        S4.w = 5;
-        s.set_i16_4(S4);
-
-        Int2 I2 = s.get_u16_2();
-        if (I2.x != 1 || I2.y != 2) {
-            return false;
-        }
-        I2.x = 2;
-        I2.y = 3;
-        s.set_u16_2(I2);
-
-        Int3 I3 = s.get_u16_3();
-        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
-            return false;
-        }
-        I3.x = 2;
-        I3.y = 3;
-        I3.z = 4;
-        s.set_u16_3(I3);
-
-        Int4 I4 = s.get_u16_4();
-        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
-            return false;
-        }
-        I4.x = 2;
-        I4.y = 3;
-        I4.z = 4;
-        I4.w = 5;
-        s.set_u16_4(I4);
-
-        I2 = s.get_i32_2();
-        if (I2.x != 1 || I2.y != 2) {
-            return false;
-        }
-        I2.x = 2;
-        I2.y = 3;
-        s.set_i32_2(I2);
-
-        I3 = s.get_i32_3();
-        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
-            return false;
-        }
-        I3.x = 2;
-        I3.y = 3;
-        I3.z = 4;
-        s.set_i32_3(I3);
-
-        I4 = s.get_i32_4();
-        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
-            return false;
-        }
-        I4.x = 2;
-        I4.y = 3;
-        I4.z = 4;
-        I4.w = 5;
-        s.set_i32_4(I4);
-
-        Long2 L2 = s.get_u32_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_u32_2(L2);
-
-        Long3 L3 = s.get_u32_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_u32_3(L3);
-
-        Long4 L4 = s.get_u32_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_u32_4(L4);
-
-        L2 = s.get_i64_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_i64_2(L2);
-
-        L3 = s.get_i64_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_i64_3(L3);
-
-        L4 = s.get_i64_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_i64_4(L4);
-
-        L2 = s.get_u64_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_u64_2(L2);
-
-        L3 = s.get_u64_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_u64_3(L3);
-
-        L4 = s.get_u64_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_u64_4(L4);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_vector s = new ScriptC_vector(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            failTest();
-        } else {
-            s.invoke_vector_test();
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UnitTest.java
deleted file mode 100644
index 01abf2f..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/UnitTest.java
+++ /dev/null
@@ -1,144 +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 com.android.rs.test_compat;
-import android.content.Context;
-import android.util.Log;
-import android.support.v8.renderscript.RenderScript.RSMessageHandler;
-
-public class UnitTest extends Thread {
-    public String name;
-    private int result;
-    private ScriptField_ListAllocs_s.Item mItem;
-    private RSTestCore mRSTC;
-    private boolean msgHandled;
-    protected Context mCtx;
-
-    /* These constants must match those in shared.rsh */
-    public static final int RS_MSG_TEST_PASSED = 100;
-    public static final int RS_MSG_TEST_FAILED = 101;
-
-    private static int numTests = 0;
-    public int testID;
-
-    protected UnitTest(RSTestCore rstc, String n, int initResult, Context ctx) {
-        super();
-        mRSTC = rstc;
-        name = n;
-        msgHandled = false;
-        mCtx = ctx;
-        result = initResult;
-        testID = numTests++;
-    }
-
-    protected UnitTest(RSTestCore rstc, String n, Context ctx) {
-        this(rstc, n, 0, ctx);
-    }
-
-    protected UnitTest(RSTestCore rstc, Context ctx) {
-        this (rstc, "<Unknown>", ctx);
-    }
-
-    protected UnitTest(Context ctx) {
-        this (null, ctx);
-    }
-
-    protected void _RS_ASSERT(String message, boolean b) {
-        if(b == false) {
-            Log.e(name, message + " FAILED");
-            failTest();
-        }
-    }
-
-    private void updateUI() {
-        if (mItem != null) {
-            mItem.result = result;
-            msgHandled = true;
-            try {
-                mRSTC.refreshTestResults();
-            }
-            catch (IllegalStateException e) {
-                /* Ignore the case where our message receiver has been
-                   disconnected. This happens when we leave the application
-                   before it finishes running all of the unit tests. */
-            }
-        }
-    }
-
-    protected RSMessageHandler mRsMessage = new RSMessageHandler() {
-        public void run() {
-            if (result == 0) {
-                switch (mID) {
-                    case RS_MSG_TEST_PASSED:
-                        result = 1;
-                        break;
-                    case RS_MSG_TEST_FAILED:
-                        result = -1;
-                        break;
-                    default:
-                        RSTest.log("Unit test got unexpected message");
-                        return;
-                }
-            }
-
-            updateUI();
-        }
-    };
-
-    public void waitForMessage() {
-        while (!msgHandled) {
-            yield();
-        }
-    }
-
-    public int getResult() {
-        return result;
-    }
-
-    public void failTest() {
-        result = -1;
-        updateUI();
-    }
-
-    public void passTest() {
-        if (result != -1) {
-            result = 1;
-        }
-        updateUI();
-    }
-
-    public String toString() {
-        String out = name;
-        if (result == 1) {
-            out += " - PASSED";
-        }
-        else if (result == -1) {
-            out += " - FAILED";
-        }
-        return out;
-    }
-
-    public void setItem(ScriptField_ListAllocs_s.Item item) {
-        mItem = item;
-    }
-
-    public void run() {
-        /* This method needs to be implemented for each subclass */
-        if (mRSTC != null) {
-            mRSTC.refreshTestResults();
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
deleted file mode 100644
index 1b5e2ac..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/alloc.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "shared.rsh"
-
-int *a;
-int dimX;
-int dimY;
-int dimZ;
-
-rs_allocation aRaw;
-rs_allocation aFaces;
-rs_allocation aLOD;
-rs_allocation aFacesLOD;
-
-void root(int *o, uint32_t x, uint32_t y) {
-    *o = x + y * dimX;
-}
-
-static bool test_alloc_dims() {
-    bool failed = false;
-    int i, j;
-
-    _RS_ASSERT(rsAllocationGetDimX(aRaw) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aRaw) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aRaw) == dimZ);
-
-    // Test 2D addressing
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(aRaw, i, j);
-            int val = *(const int *)p;
-            _RS_ASSERT(val == (i + j * dimX));
-        }
-    }
-
-    // Test 1D addressing
-    for (i = 0; i < dimX; i++) {
-        rsDebug("Verifying ", i);
-        const void *p = rsGetElementAt(aRaw, i);
-        int val = *(const int *)p;
-        _RS_ASSERT(val == i);
-    }
-
-    // Test 3D addressing
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(aRaw, i, j, 0);
-            int val = *(const int *)p;
-            _RS_ASSERT(val == (i + j * dimX));
-        }
-    }
-
-    _RS_ASSERT(rsAllocationGetDimX(aFaces) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aFaces) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aFaces) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aFaces) != 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aFaces) == 0);
-
-    _RS_ASSERT(rsAllocationGetDimX(aLOD) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aLOD) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aLOD) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aLOD) == 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aLOD) != 0);
-
-    _RS_ASSERT(rsAllocationGetDimX(aFacesLOD) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aFacesLOD) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aFacesLOD) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aFacesLOD) != 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aFacesLOD) != 0);
-
-    if (failed) {
-        rsDebug("test_alloc_dims FAILED", 0);
-    }
-    else {
-        rsDebug("test_alloc_dims PASSED", 0);
-    }
-
-    return failed;
-}
-
-void alloc_test() {
-    bool failed = false;
-    failed |= test_alloc_dims();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/array_alloc.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/array_alloc.rs
deleted file mode 100644
index 74ffdb1..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/array_alloc.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "shared.rsh"
-
-const int dimX = 20;
-rs_allocation a[dimX];
-
-void array_alloc_test() {
-    bool failed = false;
-
-    for (int i = 0; i < dimX; i++) {
-        rsDebug("i: ", i);
-        _RS_ASSERT(rsAllocationGetDimX(a[i]) == 1);
-    }
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/array_init.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/array_init.rs
deleted file mode 100644
index 842249a..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/array_init.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "shared.rsh"
-
-// Testing constant array initialization
-float fa[4] = {1.0, 9.9999f};
-double da[2] = {7.0, 8.88888};
-char ca[4] = {'a', 7, 'b', 'c'};
-short sa[4] = {1, 1, 2, 3};
-int ia[4] = {5, 8};
-long la[2] = {13, 21};
-long long lla[4] = {34};
-bool ba[3] = {true, false};
-
-void array_init_test() {
-    bool failed = false;
-
-    _RS_ASSERT(fa[0] == 1.0);
-    _RS_ASSERT(fa[1] == 9.9999f);
-    _RS_ASSERT(fa[2] == 0);
-    _RS_ASSERT(fa[3] == 0);
-
-    _RS_ASSERT(da[0] == 7.0);
-    _RS_ASSERT(da[1] == 8.88888);
-
-    _RS_ASSERT(ca[0] == 'a');
-    _RS_ASSERT(ca[1] == 7);
-    _RS_ASSERT(ca[2] == 'b');
-    _RS_ASSERT(ca[3] == 'c');
-
-    _RS_ASSERT(sa[0] == 1);
-    _RS_ASSERT(sa[1] == 1);
-    _RS_ASSERT(sa[2] == 2);
-    _RS_ASSERT(sa[3] == 3);
-
-    _RS_ASSERT(ia[0] == 5);
-    _RS_ASSERT(ia[1] == 8);
-    _RS_ASSERT(ia[2] == 0);
-    _RS_ASSERT(ia[3] == 0);
-
-    _RS_ASSERT(la[0] == 13);
-    _RS_ASSERT(la[1] == 21);
-
-    _RS_ASSERT(lla[0] == 34);
-    _RS_ASSERT(lla[1] == 0);
-    _RS_ASSERT(lla[2] == 0);
-    _RS_ASSERT(lla[3] == 0);
-
-    _RS_ASSERT(ba[0] == true);
-    _RS_ASSERT(ba[1] == false);
-    _RS_ASSERT(ba[2] == false);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/atomic.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/atomic.rs
deleted file mode 100644
index f0a5041..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/atomic.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "shared.rsh"
-
-// Testing atomic operations
-static bool testUMax(uint32_t dst, uint32_t src) {
-    bool failed = false;
-    uint32_t old = dst;
-    uint32_t expect = (dst > src ? dst : src);
-    uint32_t ret = rsAtomicMax(&dst, src);
-    _RS_ASSERT(old == ret);
-    _RS_ASSERT(dst == expect);
-    return failed;
-}
-
-static bool testUMin(uint32_t dst, uint32_t src) {
-    bool failed = false;
-    uint32_t old = dst;
-    uint32_t expect = (dst < src ? dst : src);
-    uint32_t ret = rsAtomicMin(&dst, src);
-    _RS_ASSERT(old == ret);
-    _RS_ASSERT(dst == expect);
-    return failed;
-}
-
-static bool testUCas(uint32_t dst, uint32_t cmp, uint32_t swp) {
-    bool failed = false;
-    uint32_t old = dst;
-    uint32_t expect = (dst == cmp ? swp : dst);
-    uint32_t ret = rsAtomicCas(&dst, cmp, swp);
-    _RS_ASSERT(old == ret);
-    _RS_ASSERT(dst == expect);
-    return failed;
-}
-
-static bool test_atomics() {
-    bool failed = false;
-
-    failed |= testUMax(5, 6);
-    failed |= testUMax(6, 5);
-    failed |= testUMax(5, 0xf0000006);
-    failed |= testUMax(0xf0000006, 5);
-
-    failed |= testUMin(5, 6);
-    failed |= testUMin(6, 5);
-    failed |= testUMin(5, 0xf0000006);
-    failed |= testUMin(0xf0000006, 5);
-
-    failed |= testUCas(4, 4, 5);
-    failed |= testUCas(4, 5, 5);
-    failed |= testUCas(5, 5, 4);
-    failed |= testUCas(5, 4, 4);
-    failed |= testUCas(0xf0000004, 0xf0000004, 0xf0000005);
-    failed |= testUCas(0xf0000004, 0xf0000005, 0xf0000005);
-    failed |= testUCas(0xf0000005, 0xf0000005, 0xf0000004);
-    failed |= testUCas(0xf0000005, 0xf0000004, 0xf0000004);
-
-    if (failed) {
-        rsDebug("test_atomics FAILED", 0);
-    }
-    else {
-        rsDebug("test_atomics PASSED", 0);
-    }
-
-    return failed;
-}
-
-void atomic_test() {
-    bool failed = false;
-    failed |= test_atomics();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/bug_char.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/bug_char.rs
deleted file mode 100644
index dcd7b72..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/bug_char.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "shared.rsh"
-
-char rand_sc1_0, rand_sc1_1;
-char2 rand_sc2_0, rand_sc2_1;
-
-char min_rand_sc1_sc1;
-char2 min_rand_sc2_sc2;
-
-static bool test_bug_char() {
-    bool failed = false;
-
-    rsDebug("rand_sc2_0.x: ", rand_sc2_0.x);
-    rsDebug("rand_sc2_0.y: ", rand_sc2_0.y);
-    rsDebug("rand_sc2_1.x: ", rand_sc2_1.x);
-    rsDebug("rand_sc2_1.y: ", rand_sc2_1.y);
-    char temp_sc1;
-    char2 temp_sc2;
-
-    temp_sc1 = min( rand_sc1_0, rand_sc1_1 );
-    if (temp_sc1 != min_rand_sc1_sc1) {
-        rsDebug("temp_sc1", temp_sc1);
-        failed = true;
-    }
-    rsDebug("broken", 'y');
-
-    temp_sc2 = min( rand_sc2_0, rand_sc2_1 );
-    if (temp_sc2.x != min_rand_sc2_sc2.x
-            || temp_sc2.y != min_rand_sc2_sc2.y) {
-        failed = true;
-    }
-
-
-    return failed;
-}
-
-void bug_char_test() {
-    bool failed = false;
-    failed |= test_bug_char();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/clamp.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/clamp.rs
deleted file mode 100644
index 28b00bd..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/clamp.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "shared.rsh"
-
-static bool test_clamp_vector() {
-    bool failed = false;
-
-    float2 src2 = { 2.0f, 2.0f};
-    float2 min2 = { 0.5f, -3.0f};
-    float2 max2 = { 1.0f, 9.0f};
-
-    float2 res2 = clamp(src2, min2, max2);
-    _RS_ASSERT(res2.x == 1.0f);
-    _RS_ASSERT(res2.y == 2.0f);
-
-
-    float3 src3 = { 2.0f, 2.0f, 1.0f};
-    float3 min3 = { 0.5f, -3.0f, 3.0f};
-    float3 max3 = { 1.0f, 9.0f, 4.0f};
-
-    float3 res3 = clamp(src3, min3, max3);
-    _RS_ASSERT(res3.x == 1.0f);
-    _RS_ASSERT(res3.y == 2.0f);
-    _RS_ASSERT(res3.z == 3.0f);
-
-
-    float4 src4 = { 2.0f, 2.0f, 1.0f, 4.0f };
-    float4 min4 = { 0.5f, -3.0f, 3.0f, 4.0f };
-    float4 max4 = { 1.0f, 9.0f, 4.0f, 4.0f };
-
-    float4 res4 = clamp(src4, min4, max4);
-    _RS_ASSERT(res4.x == 1.0f);
-    _RS_ASSERT(res4.y == 2.0f);
-    _RS_ASSERT(res4.z == 3.0f);
-    _RS_ASSERT(res4.w == 4.0f);
-
-    if (failed) {
-        rsDebug("test_clamp_vector FAILED", 0);
-    }
-    else {
-        rsDebug("test_clamp_vector PASSED", 0);
-    }
-
-    return failed;
-}
-
-void clamp_test() {
-    bool failed = false;
-    failed |= test_clamp_vector();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/clamp_relaxed.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/clamp_relaxed.rs
deleted file mode 100644
index 71c65ae..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/clamp_relaxed.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "clamp.rs"
-#pragma rs_fp_relaxed
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/constant.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/constant.rs
deleted file mode 100644
index 732eaef..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/constant.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "shared.rsh"
-
-const float floatTest = 1.99f;
-const double doubleTest = 2.05;
-const char charTest = -8;
-const short shortTest = -16;
-const int intTest = -32;
-const long longTest = 17179869184l; // 1 << 34
-const long long longlongTest = 68719476736l; // 1 << 36
-
-const uchar ucharTest = 8;
-const ushort ushortTest = 16;
-const uint uintTest = 32;
-const ulong ulongTest = 4611686018427387904L;
-const int64_t int64_tTest = -17179869184l; // - 1 << 34
-const uint64_t uint64_tTest = 117179869184l;
-
-const bool boolTest = true;
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/convert.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/convert.rs
deleted file mode 100644
index e314f2b..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/convert.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "shared.rsh"
-
-float4 f4 = { 2.0f, 4.0f, 6.0f, 8.0f };
-
-char4 i8_4 = { -1, -2, -3, 4 };
-
-static bool test_convert() {
-    bool failed = false;
-
-    f4 = convert_float4(i8_4);
-    _RS_ASSERT(f4.x == -1.0f);
-    _RS_ASSERT(f4.y == -2.0f);
-    _RS_ASSERT(f4.z == -3.0f);
-    _RS_ASSERT(f4.w == 4.0f);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-void convert_test() {
-    bool failed = false;
-    failed |= test_convert();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/convert_relaxed.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/convert_relaxed.rs
deleted file mode 100644
index 81abb9b..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/convert_relaxed.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "convert.rs"
-#pragma rs_fp_relaxed
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/copy_test.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/copy_test.rs
deleted file mode 100644
index f4243eb..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/copy_test.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-#include "shared.rsh"
-
-void sendResult(bool pass) {
-    if (pass) {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-}
-
-
-float2 __attribute((kernel)) copyFloat2(float2 i) {
-    return i;
-}
-
-float3 __attribute((kernel)) copyFloat3(float3 i) {
-    return i;
-}
-
-float4 __attribute((kernel)) copyFloat4(float4 i) {
-    return i;
-}
-
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/element.rs
deleted file mode 100644
index 1f24775..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/element.rs
+++ /dev/null
@@ -1,156 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_element simpleElem;
-rs_element complexElem;
-typedef struct ComplexStruct {
-    float subElem0;
-    float subElem1;
-    int subElem2;
-    float arrayElem0[2];
-    int arrayElem1[5];
-    char subElem3;
-    float subElem4;
-    float2 subElem5;
-    float3 subElem6;
-    float4 subElem_7;
-} ComplexStruct_t;
-
-ComplexStruct_t *complexStruct;
-
-static const char *subElemNames[] = {
-    "subElem0",
-    "subElem1",
-    "subElem2",
-    "arrayElem0",
-    "arrayElem1",
-    "subElem3",
-    "subElem4",
-    "subElem5",
-    "subElem6",
-    "subElem_7",
-};
-
-static uint32_t subElemNamesSizes[] = {
-    8,
-    8,
-    8,
-    10,
-    10,
-    8,
-    8,
-    8,
-    8,
-    9,
-};
-
-static uint32_t subElemArraySizes[] = {
-    1,
-    1,
-    1,
-    2,
-    5,
-    1,
-    1,
-    1,
-    1,
-    1,
-};
-
-static void resetStruct() {
-    uint8_t *bytePtr = (uint8_t*)complexStruct;
-    uint32_t sizeOfStruct = sizeof(*complexStruct);
-    for(uint32_t i = 0; i < sizeOfStruct; i ++) {
-        bytePtr[i] = 0;
-    }
-}
-
-static bool equals(const char *name0, const char * name1, uint32_t len) {
-    for (uint32_t i = 0; i < len; i ++) {
-        if (name0[i] != name1[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-static bool test_element_getters() {
-    bool failed = false;
-
-    uint32_t subElemOffsets[10];
-    uint32_t index = 0;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7  - (uint32_t)complexStruct;
-
-    uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
-    _RS_ASSERT(subElemCount == 0);
-    _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
-    _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3);
-
-    subElemCount = rsElementGetSubElementCount(complexElem);
-    _RS_ASSERT(subElemCount == 10);
-    _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
-    _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
-    _RS_ASSERT(rsElementGetBytesSize(complexElem) == sizeof(*complexStruct));
-
-    char buffer[64];
-    for (uint32_t i = 0; i < subElemCount; i ++) {
-        rs_element subElem = rsElementGetSubElement(complexElem, i);
-        _RS_ASSERT(rsIsObject(subElem));
-
-        _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
-
-        uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
-        _RS_ASSERT(written == subElemNamesSizes[i]);
-        _RS_ASSERT(equals(buffer, subElemNames[i], written));
-
-        _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
-        _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
-    }
-
-    // Tests error checking
-    rs_element subElem = rsElementGetSubElement(complexElem, subElemCount);
-    _RS_ASSERT(!rsIsObject(subElem));
-
-    _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0);
-
-    _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0);
-    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0);
-    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0);
-    uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5);
-    _RS_ASSERT(written == 4);
-    _RS_ASSERT(buffer[4] == '\0');
-
-    _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0);
-    _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0);
-
-    if (failed) {
-        rsDebug("test_element_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_element_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void element_test() {
-    bool failed = false;
-    failed |= test_element_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
deleted file mode 100644
index 08e6bed..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "shared.rsh"
-
-rs_allocation aRaw;
-int dimX;
-int dimY;
-static bool failed = false;
-
-void root(int *out, uint32_t x, uint32_t y) {
-    *out = x + y * dimX;
-}
-
-void foo(const int *in, int *out, uint32_t x, uint32_t y) {
-    _RS_ASSERT(*in == (x + y * dimX));
-    *out = 99 + x + y * dimX;
-    _RS_ASSERT(*out == (99 + x + y * dimX));
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            _RS_ASSERT(v == (i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-static bool test_foo_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            _RS_ASSERT(v == (99 + i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_foo_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_foo_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void verify_foo() {
-    failed |= test_foo_output();
-}
-
-void foreach_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
deleted file mode 100644
index 89df090..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/foreach_bounds.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "shared.rsh"
-
-int dimX;
-int dimY;
-int xStart = 0;
-int xEnd = 0;
-int yStart = 0;
-int yEnd = 0;
-
-rs_script s;
-rs_allocation aRaw;
-rs_allocation ain;
-rs_allocation aout;
-
-void root(int *out, uint32_t x, uint32_t y) {
-    *out = x + y * dimX;
-}
-
-int __attribute__((kernel)) zero() {
-    return 0;
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            rsDebug("i: ", i);
-            rsDebug("j: ", j);
-            rsDebug("a[j][i]: ", v);
-            if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
-                _RS_ASSERT(v == 0);
-            } else {
-                _RS_ASSERT(v == (i + j * dimX));
-            }
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void foreach_bounds_test() {
-    static bool failed = false;
-
-    rs_script_call_t rssc = {0};
-    rssc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
-    rssc.xStart = xStart;
-    rssc.xEnd = xEnd;
-    rssc.yStart = yStart;
-    rssc.yEnd = yEnd;
-
-    rsForEach(s, ain, aout, NULL, 0, &rssc);
-
-    failed |= test_root_output();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/fp_mad.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/fp_mad.rs
deleted file mode 100644
index b6f2b2a6..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/fp_mad.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "shared.rsh"
-
-const int TEST_COUNT = 1;
-
-static float data_f1[1025];
-static float4 data_f4[1025];
-
-static void test_mad4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 80); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = (data_f4[i] * 0.02f +
-                          data_f4[i+1] * 0.04f +
-                          data_f4[i+2] * 0.05f +
-                          data_f4[i+3] * 0.1f +
-                          data_f4[i+4] * 0.2f +
-                          data_f4[i+5] * 0.2f +
-                          data_f4[i+6] * 0.1f +
-                          data_f4[i+7] * 0.05f +
-                          data_f4[i+8] * 0.04f +
-                          data_f4[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad4 M ops", 1000.f / time);
-}
-
-static void test_mad(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 20); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = (data_f1[i] * 0.02f +
-                          data_f1[i+1] * 0.04f +
-                          data_f1[i+2] * 0.05f +
-                          data_f1[i+3] * 0.1f +
-                          data_f1[i+4] * 0.2f +
-                          data_f1[i+5] * 0.2f +
-                          data_f1[i+6] * 0.1f +
-                          data_f1[i+7] * 0.05f +
-                          data_f1[i+8] * 0.04f +
-                          data_f1[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad M ops", 1000.f / time);
-}
-
-static void test_norm(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = normalize(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_norm M ops", 10.f / time);
-}
-
-static void test_sincos4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10 / 4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = sin(data_f4[i]) * cos(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos4 M ops", 10.f / time);
-}
-
-static void test_sincos(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = sin(data_f1[i]) * cos(data_f1[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos M ops", 10.f / time);
-}
-
-static void test_clamp(uint32_t index) {
-    start();
-
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp M ops", 100.f / time);
-
-    start();
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            if (data_f1[i] < -1.f) data_f1[i] = -1.f;
-            if (data_f1[i] > -1.f) data_f1[i] = 1.f;
-        }
-    }
-
-    time = end(index);
-    rsDebug("fp_clamp ref M ops", 100.f / time);
-}
-
-static void test_clamp4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100 /4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp4 M ops", 100.f / time);
-}
-
-void fp_mad_test(uint32_t index, int test_num) {
-    int x;
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f;
-        data_f4[x].x = (x & 0xf) * 0.1f;
-        data_f4[x].y = (x & 0xf0) * 0.1f;
-        data_f4[x].z = (x & 0x33) * 0.1f;
-        data_f4[x].w = (x & 0x77) * 0.1f;
-    }
-
-    test_mad4(index);
-    test_mad(index);
-
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].x = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].y = (x & 0xf0) * 0.1f + 1.f;
-        data_f4[x].z = (x & 0x33) * 0.1f + 1.f;
-        data_f4[x].w = (x & 0x77) * 0.1f + 1.f;
-    }
-
-    test_norm(index);
-    test_sincos4(index);
-    test_sincos(index);
-    test_clamp4(index);
-    test_clamp(index);
-
-    // TODO Actually verify test result accuracy
-    rsDebug("fp_mad_test PASSED", 0);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/int4.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/int4.rs
deleted file mode 100644
index c791cab..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/int4.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "shared.rsh"
-#pragma rs_fp_relaxed
-
-uchar4 u4 = 4;
-int4 gi4 = {2, 2, 2, 2};
-
-void int4_test() {
-    bool failed = false;
-    int4 i4 = {u4.x, u4.y, u4.z, u4.w};
-    i4 *= gi4;
-
-    rsDebug("i4.x", i4.x);
-    rsDebug("i4.y", i4.y);
-    rsDebug("i4.z", i4.z);
-    rsDebug("i4.w", i4.w);
-
-    _RS_ASSERT(i4.x == 8);
-    _RS_ASSERT(i4.y == 8);
-    _RS_ASSERT(i4.z == 8);
-    _RS_ASSERT(i4.w == 8);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/kernel.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/kernel.rs
deleted file mode 100644
index d6c9df3..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/kernel.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "shared.rsh"
-
-int *ain;
-int *aout;
-int dimX;
-static bool failed = false;
-
-void init_vars(int *out) {
-    *out = 7;
-}
-
-
-int __attribute__((kernel)) root(int ain, uint32_t x) {
-    _RS_ASSERT(ain == 7);
-    return ain + x;
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i;
-
-    for (i = 0; i < dimX; i++) {
-        _RS_ASSERT(aout[i] == (i + ain[i]));
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void kernel_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/kernel_struct.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/kernel_struct.rs
deleted file mode 100644
index 62c30ae..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/kernel_struct.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "shared.rsh"
-
-struct simpleStruct {
-    int i1;
-    char ignored1;
-    float f1;
-    int i2;
-    char ignored2;
-    float f2;
-};
-
-struct simpleStruct *ain;
-struct simpleStruct *aout;
-int dimX;
-static bool failed = false;
-
-void init_vars(struct simpleStruct *out, uint32_t x) {
-    out->i1 = 0;
-    out->f1 = 0.f;
-    out->i2 = 1;
-    out->f2 = 1.0f;
-}
-
-struct simpleStruct __attribute__((kernel))
-        root(struct simpleStruct in, uint32_t x) {
-    struct simpleStruct s;
-    s.i1 = in.i1 + x;
-    s.f1 = in.f1 + x;
-    s.i2 = in.i2 + x;
-    s.f2 = in.f2 + x;
-    return s;
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i;
-
-    for (i = 0; i < dimX; i++) {
-        _RS_ASSERT(aout[i].i1 == (i + ain[i].i1));
-        _RS_ASSERT(aout[i].f1 == (i + ain[i].f1));
-        _RS_ASSERT(aout[i].i2 == (i + ain[i].i2));
-        _RS_ASSERT(aout[i].f2 == (i + ain[i].f2));
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void kernel_struct_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math.rs
deleted file mode 100644
index aae29a4..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math.rs
+++ /dev/null
@@ -1,436 +0,0 @@
-#include "shared.rsh"
-
-// Testing math library
-
-volatile float f1;
-volatile float2 f2;
-volatile float3 f3;
-volatile float4 f4;
-
-volatile int i1;
-volatile int2 i2;
-volatile int3 i3;
-volatile int4 i4;
-
-volatile uint ui1;
-volatile uint2 ui2;
-volatile uint3 ui3;
-volatile uint4 ui4;
-
-volatile short s1;
-volatile short2 s2;
-volatile short3 s3;
-volatile short4 s4;
-
-volatile ushort us1;
-volatile ushort2 us2;
-volatile ushort3 us3;
-volatile ushort4 us4;
-
-volatile char c1;
-volatile char2 c2;
-volatile char3 c3;
-volatile char4 c4;
-
-volatile uchar uc1;
-volatile uchar2 uc2;
-volatile uchar3 uc3;
-volatile uchar4 uc4;
-
-#define DECL_INT(prefix)            \
-volatile char prefix##_c_1 = 1;     \
-volatile char2 prefix##_c_2 = 1;    \
-volatile char3 prefix##_c_3 = 1;    \
-volatile char4 prefix##_c_4 = 1;    \
-volatile uchar prefix##_uc_1 = 1;   \
-volatile uchar2 prefix##_uc_2 = 1;  \
-volatile uchar3 prefix##_uc_3 = 1;  \
-volatile uchar4 prefix##_uc_4 = 1;  \
-volatile short prefix##_s_1 = 1;    \
-volatile short2 prefix##_s_2 = 1;   \
-volatile short3 prefix##_s_3 = 1;   \
-volatile short4 prefix##_s_4 = 1;   \
-volatile ushort prefix##_us_1 = 1;  \
-volatile ushort2 prefix##_us_2 = 1; \
-volatile ushort3 prefix##_us_3 = 1; \
-volatile ushort4 prefix##_us_4 = 1; \
-volatile int prefix##_i_1 = 1;      \
-volatile int2 prefix##_i_2 = 1;     \
-volatile int3 prefix##_i_3 = 1;     \
-volatile int4 prefix##_i_4 = 1;     \
-volatile uint prefix##_ui_1 = 1;    \
-volatile uint2 prefix##_ui_2 = 1;   \
-volatile uint3 prefix##_ui_3 = 1;   \
-volatile uint4 prefix##_ui_4 = 1;   \
-volatile long prefix##_l_1 = 1;     \
-volatile ulong prefix##_ul_1 = 1;
-
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
-
-#define TEST_INT_OP_TYPE(op, type)                      \
-rsDebug("Testing " #op " for " #type "1", i++);         \
-res_##type##_1 = src1_##type##_1 op src2_##type##_1;    \
-rsDebug("Testing " #op " for " #type "2", i++);         \
-res_##type##_2 = src1_##type##_2 op src2_##type##_2;    \
-rsDebug("Testing " #op " for " #type "3", i++);         \
-res_##type##_3 = src1_##type##_3 op src2_##type##_3;    \
-rsDebug("Testing " #op " for " #type "4", i++);         \
-res_##type##_4 = src1_##type##_4 op src2_##type##_4;
-
-#define TEST_INT_OP(op)                     \
-TEST_INT_OP_TYPE(op, c)                     \
-TEST_INT_OP_TYPE(op, uc)                    \
-TEST_INT_OP_TYPE(op, s)                     \
-TEST_INT_OP_TYPE(op, us)                    \
-TEST_INT_OP_TYPE(op, i)                     \
-TEST_INT_OP_TYPE(op, ui)                    \
-rsDebug("Testing " #op " for l1", i++);     \
-res_l_1 = src1_l_1 op src2_l_1;             \
-rsDebug("Testing " #op " for ul1", i++);    \
-res_ul_1 = src1_ul_1 op src2_ul_1;
-
-#define TEST_XN_FUNC_YN(typeout, fnc, typein)   \
-    res_##typeout##_1 = fnc(src1_##typein##_1); \
-    res_##typeout##_2 = fnc(src1_##typein##_2); \
-    res_##typeout##_3 = fnc(src1_##typein##_3); \
-    res_##typeout##_4 = fnc(src1_##typein##_4);
-
-#define TEST_XN_FUNC_XN_XN(type, fnc)                       \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1); \
-    res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2); \
-    res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3); \
-    res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4);
-
-#define TEST_X_FUNC_X_X_X(type, fnc)    \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src2_##type##_1);
-
-#define TEST_IN_FUNC_IN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, uc)    \
-    TEST_XN_FUNC_YN(c, fnc, c)      \
-    TEST_XN_FUNC_YN(us, fnc, us)    \
-    TEST_XN_FUNC_YN(s, fnc, s)      \
-    TEST_XN_FUNC_YN(ui, fnc, ui)    \
-    TEST_XN_FUNC_YN(i, fnc, i)
-
-#define TEST_UIN_FUNC_IN(fnc)       \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, c)     \
-    TEST_XN_FUNC_YN(us, fnc, s)     \
-    TEST_XN_FUNC_YN(ui, fnc, i)     \
-
-#define TEST_IN_FUNC_IN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_XN_XN(uc, fnc)     \
-    TEST_XN_FUNC_XN_XN(c, fnc)      \
-    TEST_XN_FUNC_XN_XN(us, fnc)     \
-    TEST_XN_FUNC_XN_XN(s, fnc)      \
-    TEST_XN_FUNC_XN_XN(ui, fnc)     \
-    TEST_XN_FUNC_XN_XN(i, fnc)
-
-#define TEST_I_FUNC_I_I_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_X_FUNC_X_X_X(uc, fnc)      \
-    TEST_X_FUNC_X_X_X(c, fnc)       \
-    TEST_X_FUNC_X_X_X(us, fnc)      \
-    TEST_X_FUNC_X_X_X(s, fnc)       \
-    TEST_X_FUNC_X_X_X(ui, fnc)      \
-    TEST_X_FUNC_X_X_X(i, fnc)
-
-#define TEST_FN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f2 = fnc(f2);                   \
-    f3 = fnc(f3);                   \
-    f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (float*) &f1);     \
-    f2 = fnc(f2, (float2*) &f2);    \
-    f3 = fnc(f3, (float3*) &f3);    \
-    f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f2);               \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_F34_FUNC_F34_F34(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f1);               \
-    f3 = fnc(f3, f1);               \
-    f4 = fnc(f4, f1);
-
-#define TEST_F_FUNC_FN(fnc)         \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f1 = fnc(f2);                   \
-    f1 = fnc(f3);                   \
-    f1 = fnc(f4);
-
-#define TEST_F_FUNC_FN_FN(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f1 = fnc(f2, f2);               \
-    f1 = fnc(f3, f3);               \
-    f1 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i2);               \
-    f3 = fnc(f3, i3);               \
-    f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i1);               \
-    f3 = fnc(f3, i1);               \
-    f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f2, f2);           \
-    f3 = fnc(f3, f3, f3);           \
-    f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_FN_F(fnc)   \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f1, f1);           \
-    f3 = fnc(f3, f1, f1);           \
-    f4 = fnc(f4, f1, f1);
-
-#define TEST_FN_FUNC_FN_PIN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (int*) &i1);       \
-    f2 = fnc(f2, (int2*) &i2);      \
-    f3 = fnc(f3, (int3*) &i3);      \
-    f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, (int*) &i1);   \
-    f2 = fnc(f2, f2, (int2*) &i2);  \
-    f3 = fnc(f3, f3, (int3*) &i3);  \
-    f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    i1 = fnc(f1);                   \
-    i2 = fnc(f2);                   \
-    i3 = fnc(f3);                   \
-    i4 = fnc(f4);
-
-static bool test_fp_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_FN_FUNC_FN(acos);
-    TEST_FN_FUNC_FN(acosh);
-    TEST_FN_FUNC_FN(acospi);
-    TEST_FN_FUNC_FN(asin);
-    TEST_FN_FUNC_FN(asinh);
-    TEST_FN_FUNC_FN(asinpi);
-    TEST_FN_FUNC_FN(atan);
-    TEST_FN_FUNC_FN_FN(atan2);
-    TEST_FN_FUNC_FN(atanh);
-    TEST_FN_FUNC_FN(atanpi);
-    TEST_FN_FUNC_FN_FN(atan2pi);
-    TEST_FN_FUNC_FN(cbrt);
-    TEST_FN_FUNC_FN(ceil);
-    TEST_FN_FUNC_FN_FN_FN(clamp);
-    TEST_FN_FUNC_FN_FN_F(clamp);
-    TEST_FN_FUNC_FN_FN(copysign);
-    TEST_FN_FUNC_FN(cos);
-    TEST_FN_FUNC_FN(cosh);
-    TEST_FN_FUNC_FN(cospi);
-    TEST_F34_FUNC_F34_F34(cross);
-    TEST_FN_FUNC_FN(degrees);
-    TEST_F_FUNC_FN_FN(distance);
-    TEST_F_FUNC_FN_FN(dot);
-    TEST_FN_FUNC_FN(erfc);
-    TEST_FN_FUNC_FN(erf);
-    TEST_FN_FUNC_FN(exp);
-    TEST_FN_FUNC_FN(exp2);
-    TEST_FN_FUNC_FN(exp10);
-    TEST_FN_FUNC_FN(expm1);
-    TEST_FN_FUNC_FN(fabs);
-    TEST_FN_FUNC_FN_FN(fdim);
-    TEST_FN_FUNC_FN(floor);
-    TEST_FN_FUNC_FN_FN_FN(fma);
-    TEST_FN_FUNC_FN_FN(fmax);
-    TEST_FN_FUNC_FN_F(fmax);
-    TEST_FN_FUNC_FN_FN(fmin);
-    TEST_FN_FUNC_FN_F(fmin);
-    TEST_FN_FUNC_FN_FN(fmod);
-    TEST_FN_FUNC_FN_PFN(fract);
-    TEST_FN_FUNC_FN_PIN(frexp);
-    TEST_FN_FUNC_FN_FN(hypot);
-    TEST_IN_FUNC_FN(ilogb);
-    TEST_FN_FUNC_FN_IN(ldexp);
-    TEST_FN_FUNC_FN_I(ldexp);
-    TEST_F_FUNC_FN(length);
-    TEST_FN_FUNC_FN(lgamma);
-    TEST_FN_FUNC_FN_PIN(lgamma);
-    TEST_FN_FUNC_FN(log);
-    TEST_FN_FUNC_FN(log2);
-    TEST_FN_FUNC_FN(log10);
-    TEST_FN_FUNC_FN(log1p);
-    TEST_FN_FUNC_FN(logb);
-    TEST_FN_FUNC_FN_FN_FN(mad);
-    TEST_FN_FUNC_FN_FN(max);
-    TEST_FN_FUNC_FN_F(max);
-    TEST_FN_FUNC_FN_FN(min);
-    TEST_FN_FUNC_FN_F(min);
-    TEST_FN_FUNC_FN_FN_FN(mix);
-    TEST_FN_FUNC_FN_FN_F(mix);
-    TEST_FN_FUNC_FN_PFN(modf);
-    // nan
-    TEST_FN_FUNC_FN_FN(nextafter);
-    TEST_FN_FUNC_FN(normalize);
-    TEST_FN_FUNC_FN_FN(pow);
-    TEST_FN_FUNC_FN_IN(pown);
-    TEST_FN_FUNC_FN_FN(powr);
-    TEST_FN_FUNC_FN(radians);
-    TEST_FN_FUNC_FN_FN(remainder);
-    TEST_FN_FUNC_FN_FN_PIN(remquo);
-    TEST_FN_FUNC_FN(rint);
-    TEST_FN_FUNC_FN_IN(rootn);
-    TEST_FN_FUNC_FN(round);
-    TEST_FN_FUNC_FN(rsqrt);
-    TEST_FN_FUNC_FN(sign);
-    TEST_FN_FUNC_FN(sin);
-    TEST_FN_FUNC_FN_PFN(sincos);
-    TEST_FN_FUNC_FN(sinh);
-    TEST_FN_FUNC_FN(sinpi);
-    TEST_FN_FUNC_FN(sqrt);
-    TEST_FN_FUNC_FN_FN(step);
-    TEST_FN_FUNC_FN_F(step);
-    TEST_FN_FUNC_FN(tan);
-    TEST_FN_FUNC_FN(tanh);
-    TEST_FN_FUNC_FN(tanpi);
-    TEST_FN_FUNC_FN(tgamma);
-    TEST_FN_FUNC_FN(trunc);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_fp_math FAILED", time);
-    }
-    else {
-        rsDebug("test_fp_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_int_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_UIN_FUNC_IN(abs);
-    TEST_IN_FUNC_IN(clz);
-    TEST_IN_FUNC_IN_IN(min);
-    TEST_IN_FUNC_IN_IN(max);
-    TEST_I_FUNC_I_I_I(rsClamp);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_int_math FAILED", time);
-    }
-    else {
-        rsDebug("test_int_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_basic_operators() {
-    bool failed = false;
-    int i = 0;
-
-    TEST_INT_OP(+);
-    TEST_INT_OP(-);
-    TEST_INT_OP(*);
-    TEST_INT_OP(/);
-    TEST_INT_OP(%);
-    TEST_INT_OP(<<);
-    TEST_INT_OP(>>);
-
-    if (failed) {
-        rsDebug("test_basic_operators FAILED", 0);
-    }
-    else {
-        rsDebug("test_basic_operators PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define TEST_CVT(to, from, type)                        \
-rsDebug("Testing convert from " #from " to " #to, 0);   \
-to##1 = from##1;                                        \
-to##2 = convert_##type##2(from##2);                     \
-to##3 = convert_##type##3(from##3);                     \
-to##4 = convert_##type##4(from##4);
-
-#define TEST_CVT_MATRIX(to, type)   \
-TEST_CVT(to, c, type);              \
-TEST_CVT(to, uc, type);             \
-TEST_CVT(to, s, type);              \
-TEST_CVT(to, us, type);             \
-TEST_CVT(to, i, type);              \
-TEST_CVT(to, ui, type);             \
-TEST_CVT(to, f, type);              \
-
-static bool test_convert() {
-    bool failed = false;
-
-    TEST_CVT_MATRIX(c, char);
-    TEST_CVT_MATRIX(uc, uchar);
-    TEST_CVT_MATRIX(s, short);
-    TEST_CVT_MATRIX(us, ushort);
-    TEST_CVT_MATRIX(i, int);
-    TEST_CVT_MATRIX(ui, uint);
-    TEST_CVT_MATRIX(f, float);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_convert();
-    failed |= test_fp_math(index);
-    failed |= test_int_math(index);
-    failed |= test_basic_operators();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math_agree.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math_agree.rs
deleted file mode 100644
index 5bfbb2b..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math_agree.rs
+++ /dev/null
@@ -1,409 +0,0 @@
-#include "shared.rsh"
-//#pragma rs_fp_relaxed
-
-volatile float x = 0.0f;
-volatile float y = 0.0f;
-volatile float result_add = 0.0f;
-volatile float result_sub = 0.0f;
-volatile float result_mul = 0.0f;
-volatile float result_div = 0.0f;
-
-#define DECLARE_INPUT_SET(type, abbrev)         \
-volatile type    rand_##abbrev##1_0, rand_##abbrev##1_1; \
-volatile type##2 rand_##abbrev##2_0, rand_##abbrev##2_1; \
-volatile type##3 rand_##abbrev##3_0, rand_##abbrev##3_1; \
-volatile type##4 rand_##abbrev##4_0, rand_##abbrev##4_1;
-
-#define DECLARE_ALL_INPUT_SETS()    \
-DECLARE_INPUT_SET(float, f);        \
-DECLARE_INPUT_SET(char, sc);        \
-DECLARE_INPUT_SET(uchar, uc);       \
-DECLARE_INPUT_SET(short, ss);       \
-DECLARE_INPUT_SET(ushort, us);      \
-DECLARE_INPUT_SET(int, si);         \
-DECLARE_INPUT_SET(uint, ui);        \
-DECLARE_INPUT_SET(long, sl);        \
-DECLARE_INPUT_SET(ulong, ul);
-
-DECLARE_ALL_INPUT_SETS();
-
-#define DECLARE_REFERENCE_SET_VEC_VEC(type, abbrev, func)   \
-volatile type    func##_rand_##abbrev##1_##abbrev##1;                \
-volatile type##2 func##_rand_##abbrev##2_##abbrev##2;                \
-volatile type##3 func##_rand_##abbrev##3_##abbrev##3;                \
-volatile type##4 func##_rand_##abbrev##4_##abbrev##4;
-#define DECLARE_REFERENCE_SET_VEC_SCL(type, abbrev, func)   \
-volatile type##2 func##_rand_##abbrev##2_##abbrev##1;                \
-volatile type##3 func##_rand_##abbrev##3_##abbrev##1;                \
-volatile type##4 func##_rand_##abbrev##4_##abbrev##1;
-
-#define DECLARE_ALL_REFERENCE_SETS_VEC_VEC(func)    \
-DECLARE_REFERENCE_SET_VEC_VEC(float, f, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(char, sc, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(uchar, uc, func);     \
-DECLARE_REFERENCE_SET_VEC_VEC(short, ss, func);     \
-DECLARE_REFERENCE_SET_VEC_VEC(ushort, us, func);    \
-DECLARE_REFERENCE_SET_VEC_VEC(int, si, func);       \
-DECLARE_REFERENCE_SET_VEC_VEC(uint, ui, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(long, sl, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(ulong, ul, func);
-
-DECLARE_ALL_REFERENCE_SETS_VEC_VEC(min);
-DECLARE_ALL_REFERENCE_SETS_VEC_VEC(max);
-DECLARE_REFERENCE_SET_VEC_VEC(float, f, fmin);
-DECLARE_REFERENCE_SET_VEC_SCL(float, f, fmin);
-DECLARE_REFERENCE_SET_VEC_VEC(float, f, fmax);
-DECLARE_REFERENCE_SET_VEC_SCL(float, f, fmax);
-
-static void fail_f1(float v1, float v2, float actual, float expected, char *op_name) {
-    int dist = float_dist(actual, expected);
-    rsDebug("float operation did not match!", op_name);
-    rsDebug("v1", v1);
-    rsDebug("v2", v2);
-    rsDebug("Dalvik result", expected);
-    rsDebug("Renderscript result", actual);
-    rsDebug("ULP difference", dist);
-}
-
-static void fail_f2(float2 v1, float2 v2, float2 actual, float2 expected, char *op_name) {
-    int2 dist;
-    dist.x = float_dist(actual.x, expected.x);
-    dist.y = float_dist(actual.y, expected.y);
-    rsDebug("float2 operation did not match!", op_name);
-    rsDebug("v1.x", v1.x);
-    rsDebug("v1.y", v1.y);
-    rsDebug("v2.x", v2.x);
-    rsDebug("v2.y", v2.y);
-    rsDebug("Dalvik result .x", expected.x);
-    rsDebug("Dalvik result .y", expected.y);
-    rsDebug("Renderscript result .x", actual.x);
-    rsDebug("Renderscript result .y", actual.y);
-    rsDebug("ULP difference .x", dist.x);
-    rsDebug("ULP difference .y", dist.y);
-}
-
-static void fail_f3(float3 v1, float3 v2, float3 actual, float3 expected, char *op_name) {
-    int3 dist;
-    dist.x = float_dist(actual.x, expected.x);
-    dist.y = float_dist(actual.y, expected.y);
-    dist.z = float_dist(actual.z, expected.z);
-    rsDebug("float3 operation did not match!", op_name);
-    rsDebug("v1.x", v1.x);
-    rsDebug("v1.y", v1.y);
-    rsDebug("v1.z", v1.z);
-    rsDebug("v2.x", v2.x);
-    rsDebug("v2.y", v2.y);
-    rsDebug("v2.z", v2.z);
-    rsDebug("Dalvik result .x", expected.x);
-    rsDebug("Dalvik result .y", expected.y);
-    rsDebug("Dalvik result .z", expected.z);
-    rsDebug("Renderscript result .x", actual.x);
-    rsDebug("Renderscript result .y", actual.y);
-    rsDebug("Renderscript result .z", actual.z);
-    rsDebug("ULP difference .x", dist.x);
-    rsDebug("ULP difference .y", dist.y);
-    rsDebug("ULP difference .z", dist.z);
-}
-
-static void fail_f4(float4 v1, float4 v2, float4 actual, float4 expected, char *op_name) {
-    int4 dist;
-    dist.x = float_dist(actual.x, expected.x);
-    dist.y = float_dist(actual.y, expected.y);
-    dist.z = float_dist(actual.z, expected.z);
-    dist.w = float_dist(actual.w, expected.w);
-    rsDebug("float4 operation did not match!", op_name);
-    rsDebug("v1.x", v1.x);
-    rsDebug("v1.y", v1.y);
-    rsDebug("v1.z", v1.z);
-    rsDebug("v1.w", v1.w);
-    rsDebug("v2.x", v2.x);
-    rsDebug("v2.y", v2.y);
-    rsDebug("v2.z", v2.z);
-    rsDebug("v2.w", v2.w);
-    rsDebug("Dalvik result .x", expected.x);
-    rsDebug("Dalvik result .y", expected.y);
-    rsDebug("Dalvik result .z", expected.z);
-    rsDebug("Dalvik result .w", expected.w);
-    rsDebug("Renderscript result .x", actual.x);
-    rsDebug("Renderscript result .y", actual.y);
-    rsDebug("Renderscript result .z", actual.z);
-    rsDebug("Renderscript result .w", actual.w);
-    rsDebug("ULP difference .x", dist.x);
-    rsDebug("ULP difference .y", dist.y);
-    rsDebug("ULP difference .z", dist.z);
-    rsDebug("ULP difference .w", dist.w);
-}
-
-static bool f1_almost_equal(float a, float b) {
-    return float_almost_equal(a, b);
-}
-
-static bool f2_almost_equal(float2 a, float2 b) {
-    return float_almost_equal(a.x, b.x) && float_almost_equal(a.y, b.y);
-}
-
-
-static bool f3_almost_equal(float3 a, float3 b) {
-    return float_almost_equal(a.x, b.x) && float_almost_equal(a.y, b.y)
-            && float_almost_equal(a.z, b.z);
-}
-
-static bool f4_almost_equal(float4 a, float4 b) {
-    return float_almost_equal(a.x, b.x) && float_almost_equal(a.y, b.y)
-            && float_almost_equal(a.z, b.z) && float_almost_equal(a.w, b.w);
-}
-
-#define TEST_BASIC_FLOAT_OP(op, opName)                 \
-temp_f1 = x op y;                                       \
-if (! float_almost_equal(temp_f1, result_##opName)) {   \
-    fail_f1(x, y , temp_f1, result_##opName, #opName);  \
-    failed = true;                                      \
-}
-
-#define TEST_FN_FN(func, size)                                                  \
-temp_f##size = func(rand_f##size##_0, rand_f##size##_1);                        \
-if (! f##size##_almost_equal(temp_f##size , func##_rand_f##size##_f##size)) {   \
-    fail_f##size (x, y , temp_f##size, func##_rand_f##size##_f##size, #func);   \
-    failed = true;                                                              \
-}
-#define TEST_FN_F(func, size)                                               \
-temp_f##size = func(rand_f##size##_0, rand_f1_1);                           \
-if (! f##size##_almost_equal(temp_f##size , func##_rand_f##size##_f1)) {    \
-    fail_f##size (x, y , temp_f##size, func##_rand_f##size##_f1 , #func);   \
-    failed = true;                                                          \
-}
-
-#define TEST_FN_FN_ALL(func)    \
-TEST_FN_FN(func, 1)             \
-TEST_FN_FN(func, 2)             \
-TEST_FN_FN(func, 3)             \
-TEST_FN_FN(func, 4)
-#define TEST_FN_F_ALL(func) \
-TEST_FN_F(func, 2)          \
-TEST_FN_F(func, 3)          \
-TEST_FN_F(func, 4)
-
-#define TEST_VEC1_VEC1(func, type)                              \
-temp_##type##1 = func( rand_##type##1_0, rand_##type##1_1 );    \
-if (temp_##type##1 != func##_rand_##type##1_##type##1) {        \
-    rsDebug(#func " " #type "1 operation did not match!", 0);   \
-    rsDebug("v1", rand_##type##1_0);                            \
-    rsDebug("v2", rand_##type##1_1);                            \
-    rsDebug("Dalvik result", func##_rand_##type##1_##type##1);  \
-    rsDebug("Renderscript result", temp_##type##1);             \
-    failed = true;                                              \
-}
-#define TEST_VEC2_VEC2(func, type)                                      \
-temp_##type##2 = func( rand_##type##2_0, rand_##type##2_1 );            \
-if (temp_##type##2 .x != func##_rand_##type##2_##type##2 .x             \
-        || temp_##type##2 .y != func##_rand_##type##2_##type##2 .y) {   \
-    rsDebug(#func " " #type "2 operation did not match!", 0);           \
-    rsDebug("v1.x", rand_##type##2_0 .x);                               \
-    rsDebug("v1.y", rand_##type##2_0 .y);                               \
-    rsDebug("v2.x", rand_##type##2_1 .x);                               \
-    rsDebug("v2.y", rand_##type##2_1 .y);                               \
-    rsDebug("Dalvik result .x", func##_rand_##type##2_##type##2 .x);    \
-    rsDebug("Dalvik result .y", func##_rand_##type##2_##type##2 .y);    \
-    rsDebug("Renderscript result .x", temp_##type##2 .x);               \
-    rsDebug("Renderscript result .y", temp_##type##2 .y);               \
-    failed = true;                                                      \
-}
-#define TEST_VEC3_VEC3(func, type)                                      \
-temp_##type##3 = func( rand_##type##3_0, rand_##type##3_1 );            \
-if (temp_##type##3 .x != func##_rand_##type##3_##type##3 .x             \
-        || temp_##type##3 .y != func##_rand_##type##3_##type##3 .y      \
-        || temp_##type##3 .z != func##_rand_##type##3_##type##3 .z) {   \
-    rsDebug(#func " " #type "3 operation did not match!", 0);           \
-    rsDebug("v1.x", rand_##type##3_0 .x);                               \
-    rsDebug("v1.y", rand_##type##3_0 .y);                               \
-    rsDebug("v1.z", rand_##type##3_0 .z);                               \
-    rsDebug("v2.x", rand_##type##3_1 .x);                               \
-    rsDebug("v2.y", rand_##type##3_1 .y);                               \
-    rsDebug("v2.z", rand_##type##3_1 .z);                               \
-    rsDebug("Dalvik result .x", func##_rand_##type##3_##type##3 .x);    \
-    rsDebug("Dalvik result .y", func##_rand_##type##3_##type##3 .y);    \
-    rsDebug("Dalvik result .z", func##_rand_##type##3_##type##3 .z);    \
-    rsDebug("Renderscript result .x", temp_##type##3 .x);               \
-    rsDebug("Renderscript result .y", temp_##type##3 .y);               \
-    rsDebug("Renderscript result .z", temp_##type##3 .z);               \
-    failed = true;                                                      \
-}
-#define TEST_VEC4_VEC4(func, type)                                      \
-temp_##type##4 = func( rand_##type##4_0, rand_##type##4_1 );            \
-if (temp_##type##4 .x != func##_rand_##type##4_##type##4 .x             \
-        || temp_##type##4 .y != func##_rand_##type##4_##type##4 .y      \
-        || temp_##type##4 .z != func##_rand_##type##4_##type##4 .z      \
-        || temp_##type##4 .w != func##_rand_##type##4_##type##4 .w) {   \
-    rsDebug(#func " " #type "4 operation did not match!", 0);           \
-    rsDebug("v1.x", rand_##type##4_0 .x);                               \
-    rsDebug("v1.y", rand_##type##4_0 .y);                               \
-    rsDebug("v1.z", rand_##type##4_0 .z);                               \
-    rsDebug("v1.w", rand_##type##4_0 .w);                               \
-    rsDebug("v2.x", rand_##type##4_1 .x);                               \
-    rsDebug("v2.y", rand_##type##4_1 .y);                               \
-    rsDebug("v2.z", rand_##type##4_1 .z);                               \
-    rsDebug("v2.w", rand_##type##4_1 .w);                               \
-    rsDebug("Dalvik result .x", func##_rand_##type##4_##type##4 .x);    \
-    rsDebug("Dalvik result .y", func##_rand_##type##4_##type##4 .y);    \
-    rsDebug("Dalvik result .z", func##_rand_##type##4_##type##4 .z);    \
-    rsDebug("Dalvik result .w", func##_rand_##type##4_##type##4 .w);    \
-    rsDebug("Renderscript result .x", temp_##type##4 .x);               \
-    rsDebug("Renderscript result .y", temp_##type##4 .y);               \
-    rsDebug("Renderscript result .z", temp_##type##4 .z);               \
-    rsDebug("Renderscript result .w", temp_##type##4 .w);               \
-    failed = true;                                                      \
-}
-
-#define TEST_SC1_SC1(func)  TEST_VEC1_VEC1(func, sc)
-#define TEST_SC2_SC2(func)  TEST_VEC2_VEC2(func, sc)
-#define TEST_SC3_SC3(func)  TEST_VEC3_VEC3(func, sc)
-#define TEST_SC4_SC4(func)  TEST_VEC4_VEC4(func, sc)
-
-#define TEST_UC1_UC1(func)  TEST_VEC1_VEC1(func, uc)
-#define TEST_UC2_UC2(func)  TEST_VEC2_VEC2(func, uc)
-#define TEST_UC3_UC3(func)  TEST_VEC3_VEC3(func, uc)
-#define TEST_UC4_UC4(func)  TEST_VEC4_VEC4(func, uc)
-
-#define TEST_SS1_SS1(func)  TEST_VEC1_VEC1(func, ss)
-#define TEST_SS2_SS2(func)  TEST_VEC2_VEC2(func, ss)
-#define TEST_SS3_SS3(func)  TEST_VEC3_VEC3(func, ss)
-#define TEST_SS4_SS4(func)  TEST_VEC4_VEC4(func, ss)
-
-#define TEST_US1_US1(func)  TEST_VEC1_VEC1(func, us)
-#define TEST_US2_US2(func)  TEST_VEC2_VEC2(func, us)
-#define TEST_US3_US3(func)  TEST_VEC3_VEC3(func, us)
-#define TEST_US4_US4(func)  TEST_VEC4_VEC4(func, us)
-
-#define TEST_SI1_SI1(func)  TEST_VEC1_VEC1(func, si)
-#define TEST_SI2_SI2(func)  TEST_VEC2_VEC2(func, si)
-#define TEST_SI3_SI3(func)  TEST_VEC3_VEC3(func, si)
-#define TEST_SI4_SI4(func)  TEST_VEC4_VEC4(func, si)
-
-#define TEST_UI1_UI1(func)  TEST_VEC1_VEC1(func, ui)
-#define TEST_UI2_UI2(func)  TEST_VEC2_VEC2(func, ui)
-#define TEST_UI3_UI3(func)  TEST_VEC3_VEC3(func, ui)
-#define TEST_UI4_UI4(func)  TEST_VEC4_VEC4(func, ui)
-
-#define TEST_SL1_SL1(func)  TEST_VEC1_VEC1(func, sl)
-#define TEST_SL2_SL2(func)  TEST_VEC2_VEC2(func, sl)
-#define TEST_SL3_SL3(func)  TEST_VEC3_VEC3(func, sl)
-#define TEST_SL4_SL4(func)  TEST_VEC4_VEC4(func, sl)
-
-#define TEST_UL1_UL1(func)  TEST_VEC1_VEC1(func, ul)
-#define TEST_UL2_UL2(func)  TEST_VEC2_VEC2(func, ul)
-#define TEST_UL3_UL3(func)  TEST_VEC3_VEC3(func, ul)
-#define TEST_UL4_UL4(func)  TEST_VEC4_VEC4(func, ul)
-
-#define TEST_SC_SC_ALL(func)    \
-TEST_SC1_SC1(func)              \
-TEST_SC2_SC2(func)              \
-TEST_SC3_SC3(func)              \
-TEST_SC4_SC4(func)
-#define TEST_UC_UC_ALL(func)    \
-TEST_UC1_UC1(func)              \
-TEST_UC2_UC2(func)              \
-TEST_UC3_UC3(func)              \
-TEST_UC4_UC4(func)
-
-#define TEST_SS_SS_ALL(func)    \
-TEST_SS1_SS1(func)              \
-TEST_SS2_SS2(func)              \
-TEST_SS3_SS3(func)              \
-TEST_SS4_SS4(func)
-#define TEST_US_US_ALL(func)    \
-TEST_US1_US1(func)              \
-TEST_US2_US2(func)              \
-TEST_US3_US3(func)              \
-TEST_US4_US4(func)
-#define TEST_SI_SI_ALL(func)    \
-TEST_SI1_SI1(func)              \
-TEST_SI2_SI2(func)              \
-TEST_SI3_SI3(func)              \
-TEST_SI4_SI4(func)
-#define TEST_UI_UI_ALL(func)    \
-TEST_UI1_UI1(func)              \
-TEST_UI2_UI2(func)              \
-TEST_UI3_UI3(func)              \
-TEST_UI4_UI4(func)
-#define TEST_SL_SL_ALL(func)    \
-TEST_SL1_SL1(func)              \
-TEST_SL2_SL2(func)              \
-TEST_SL3_SL3(func)              \
-TEST_SL4_SL4(func)
-#define TEST_UL_UL_ALL(func)    \
-TEST_UL1_UL1(func)              \
-TEST_UL2_UL2(func)              \
-TEST_UL3_UL3(func)              \
-TEST_UL4_UL4(func)
-
-#define TEST_VEC_VEC_ALL(func)  \
-TEST_FN_FN_ALL(func)            \
-TEST_SC_SC_ALL(func)            \
-TEST_UC_UC_ALL(func)            \
-TEST_SS_SS_ALL(func)            \
-TEST_US_US_ALL(func)            \
-TEST_SI_SI_ALL(func)            \
-TEST_UI_UI_ALL(func)
-
-// TODO:  add long types to ALL macro
-#if 0
-TEST_SL_SL_ALL(func)            \
-TEST_UL_UL_ALL(func)
-#endif
-
-#define DECLARE_TEMP_SET(type, abbrev)  \
-volatile type    temp_##abbrev##1;               \
-volatile type##2 temp_##abbrev##2;               \
-volatile type##3 temp_##abbrev##3;               \
-volatile type##4 temp_##abbrev##4;
-
-#define DECLARE_ALL_TEMP_SETS() \
-DECLARE_TEMP_SET(float, f);     \
-DECLARE_TEMP_SET(char, sc);     \
-DECLARE_TEMP_SET(uchar, uc);    \
-DECLARE_TEMP_SET(short, ss);    \
-DECLARE_TEMP_SET(ushort, us);   \
-DECLARE_TEMP_SET(int, si);      \
-DECLARE_TEMP_SET(uint, ui);     \
-DECLARE_TEMP_SET(long, sl);     \
-DECLARE_TEMP_SET(ulong, ul);
-
-static bool test_math_agree() {
-    bool failed = false;
-
-    DECLARE_ALL_TEMP_SETS();
-
-    TEST_BASIC_FLOAT_OP(+, add);
-    TEST_BASIC_FLOAT_OP(-, sub);
-    TEST_BASIC_FLOAT_OP(*, mul);
-    TEST_BASIC_FLOAT_OP(/, div);
-
-    TEST_VEC_VEC_ALL(min);
-    TEST_VEC_VEC_ALL(max);
-    TEST_FN_FN_ALL(fmin);
-    TEST_FN_F_ALL(fmin);
-    TEST_FN_FN_ALL(fmax);
-    TEST_FN_F_ALL(fmax);
-
-    if (failed) {
-        rsDebug("test_math_agree FAILED", 0);
-    }
-    else {
-        rsDebug("test_math_agree PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_agree_test() {
-    bool failed = false;
-    failed |= test_math_agree();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math_conformance.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math_conformance.rs
deleted file mode 100644
index 2d62f34..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/math_conformance.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "shared.rsh"
-
-// Testing math conformance
-
-static bool test_rootn() {
-    bool failed = false;
-
-    // rootn(x, 0) -> NaN
-    _RS_ASSERT(isnan(rootn(1.0f, 0)));
-
-    // rootn(+/-0, n) -> +/-inf for odd n < 0
-    _RS_ASSERT(isposinf(rootn(0.f, -3)));
-    _RS_ASSERT(isneginf(rootn(-0.f, -3)));
-
-    // rootn(+/-0, n) -> +inf for even n < 0
-    _RS_ASSERT(isposinf(rootn(0.f, -8)));
-    _RS_ASSERT(isposinf(rootn(-0.f, -8)));
-
-    // rootn(+/-0, n) -> +/-0 for odd n > 0
-    _RS_ASSERT(isposzero(rootn(0.f, 3)));
-    _RS_ASSERT(isnegzero(rootn(-0.f, 3)));
-
-    // rootn(+/-0, n) -> +0 for even n > 0
-    _RS_ASSERT(isposzero(rootn(0.f, 8)));
-    _RS_ASSERT(isposzero(rootn(-0.f, 8)));
-
-    // rootn(x, n) -> NaN for x < 0 and even n
-    _RS_ASSERT(isnan(rootn(-10000.f, -4)));
-    _RS_ASSERT(isnan(rootn(-10000.f, 4)));
-
-    // rootn(x, n) -> value for x < 0 and odd n
-    _RS_ASSERT(!isnan(rootn(-10000.f, -3)));
-    _RS_ASSERT(!isnan(rootn(-10000.f, 3)));
-
-    if (failed) {
-        rsDebug("test_rootn FAILED", -1);
-    }
-    else {
-        rsDebug("test_rootn PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_conformance_test() {
-    bool failed = false;
-    failed |= test_rootn();
-
-    if (failed) {
-        rsDebug("math_conformance_test FAILED", -1);
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsDebug("math_conformance_test PASSED", 0);
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/min.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/min.rs
deleted file mode 100644
index 4b92763..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/min.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "shared.rsh"
-#pragma rs_fp_relaxed
-
-volatile uchar2 res_uc_2 = 1;
-volatile uchar2 src1_uc_2 = 1;
-volatile uchar2 src2_uc_2 = 1;
-
-void min_test() {
-    bool failed = false;
-
-    res_uc_2 = min(src1_uc_2, src2_uc_2);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
deleted file mode 100644
index 2c807bd..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/noroot.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "shared.rsh"
-
-rs_allocation aRaw;
-int dimX;
-int dimY;
-static bool failed = false;
-
-void foo(const int *in, int *out, uint32_t x, uint32_t y) {
-    *out = 99 + x + y * dimX;
-}
-
-static bool test_foo_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            _RS_ASSERT(v == (99 + i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_foo_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_foo_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_foo() {
-    failed |= test_foo_output();
-}
-
-void noroot_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/primitives.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/primitives.rs
deleted file mode 100644
index ce451da..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/primitives.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool test_primitive_types(uint32_t index) {
-    bool failed = false;
-    start();
-
-    _RS_ASSERT(floatTest == 2.99f);
-    _RS_ASSERT(doubleTest == 3.05);
-    _RS_ASSERT(charTest == -16);
-    _RS_ASSERT(shortTest == -32);
-    _RS_ASSERT(intTest == -64);
-    _RS_ASSERT(longTest == 17179869185l);
-    _RS_ASSERT(longlongTest == 68719476735l);
-
-    _RS_ASSERT(ucharTest == 8);
-    _RS_ASSERT(ushortTest == 16);
-    _RS_ASSERT(uintTest == 32);
-    _RS_ASSERT(ulongTest == 4611686018427387903L);
-    _RS_ASSERT(int64_tTest == -17179869184l);
-    _RS_ASSERT(uint64_tTest == 117179869185l);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_primitives FAILED", time);
-    }
-    else {
-        rsDebug("test_primitives PASSED", time);
-    }
-
-    return failed;
-}
-
-void primitives_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_primitive_types(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/refcount.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/refcount.rs
deleted file mode 100644
index 4ea70e2..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/refcount.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "shared.rsh"
-
-// Testing reference counting of RS object types
-
-rs_allocation globalA;
-static rs_allocation staticGlobalA;
-
-void refcount_test() {
-    staticGlobalA = globalA;
-    rsClearObject(&globalA);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rsdebug.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rsdebug.rs
deleted file mode 100644
index 68ac168..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rsdebug.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-float2 float2Test = {2.99f, 12.99f};
-float3 float3Test = {3.99f, 13.99f, 23.99f};
-float4 float4Test = {4.99f, 14.99f, 24.99f, 34.99f};
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    // For this reason, none of the outputs are actually checked.
-
-    rsDebug("floatTest", floatTest);
-    rsDebug("float2Test", float2Test);
-    rsDebug("float3Test", float3Test);
-    rsDebug("float4Test", float4Test);
-    rsDebug("doubleTest", doubleTest);
-    rsDebug("charTest", charTest);
-    rsDebug("shortTest", shortTest);
-    rsDebug("intTest", intTest);
-    rsDebug("longTest", longTest);
-    rsDebug("longlongTest", longlongTest);
-
-    rsDebug("ucharTest", ucharTest);
-    rsDebug("ushortTest", ushortTest);
-    rsDebug("uintTest", uintTest);
-    rsDebug("ulongTest", ulongTest);
-    rsDebug("int64_tTest", int64_tTest);
-    rsDebug("uint64_tTest", uint64_tTest);
-
-    return failed;
-}
-
-void test_rsdebug(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rsdebug_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rsdebug_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rslist.rs
deleted file mode 100644
index 650243e..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rslist.rs
+++ /dev/null
@@ -1,25 +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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_compat)
-
-typedef struct ListAllocs_s {
-    rs_allocation text;
-    int result;
-} ListAllocs;
-
-ListAllocs *gList;
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rstime.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rstime.rs
deleted file mode 100644
index 7be955d..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rstime.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "shared.rsh"
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_time_t curTime = rsTime(0);
-    rs_tm tm;
-    rsDebug("curTime", curTime);
-
-    rsLocaltime(&tm, &curTime);
-
-    rsDebug("tm.tm_sec", tm.tm_sec);
-    rsDebug("tm.tm_min", tm.tm_min);
-    rsDebug("tm.tm_hour", tm.tm_hour);
-    rsDebug("tm.tm_mday", tm.tm_mday);
-    rsDebug("tm.tm_mon", tm.tm_mon);
-    rsDebug("tm.tm_year", tm.tm_year);
-    rsDebug("tm.tm_wday", tm.tm_wday);
-    rsDebug("tm.tm_yday", tm.tm_yday);
-    rsDebug("tm.tm_isdst", tm.tm_isdst);
-
-    // Test a specific time (since we set America/Los_Angeles localtime)
-    curTime = 1294438893;
-    rsLocaltime(&tm, &curTime);
-
-    _RS_ASSERT(tm.tm_sec == 33);
-    _RS_ASSERT(tm.tm_min == 21);
-    _RS_ASSERT(tm.tm_hour == 14);
-    _RS_ASSERT(tm.tm_mday == 7);
-    _RS_ASSERT(tm.tm_mon == 0);
-    _RS_ASSERT(tm.tm_year == 111);
-    _RS_ASSERT(tm.tm_wday == 5);
-    _RS_ASSERT(tm.tm_yday == 6);
-    _RS_ASSERT(tm.tm_isdst == 0);
-
-    return failed;
-}
-
-void test_rstime(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstime_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstime_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rstypes.rs
deleted file mode 100644
index bec124d..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/rstypes.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_element elementTest;
-rs_type typeTest;
-rs_allocation allocationTest;
-rs_sampler samplerTest;
-rs_script scriptTest;
-
-rs_matrix4x4 matrix4x4Test;
-rs_matrix3x3 matrix3x3Test;
-rs_matrix2x2 matrix2x2Test;
-
-struct my_struct {
-    int i;
-    rs_allocation banana;
-};
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_matrix4x4 matrix4x4TestLocal;
-    rs_matrix3x3 matrix3x3TestLocal;
-    rs_matrix2x2 matrix2x2TestLocal;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    rs_element elementTestLocal;
-    rs_type typeTestLocal;
-    rs_allocation allocationTestLocal;
-    rs_sampler samplerTestLocal;
-    rs_script scriptTestLocal;
-
-    struct my_struct structTest;
-
-    //allocationTestLocal = allocationTest;
-
-    //allocationTest = allocationTestLocal;
-
-    /*for (int i = 0; i < 4; i++) {
-        fontTestLocalArray[i] = fontTestLocal;
-    }*/
-
-    /*fontTest = fontTestLocalArray[3];*/
-
-    return failed;
-}
-
-void test_rstypes(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstypes_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstypes_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/sampler.rs
deleted file mode 100644
index ff1c0a7..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/sampler.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-rs_sampler minification;
-rs_sampler magnification;
-rs_sampler wrapS;
-rs_sampler wrapT;
-rs_sampler anisotropy;
-
-static bool test_sampler_getters() {
-    bool failed = false;
-
-    _RS_ASSERT(rsSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
-    _RS_ASSERT(rsSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(minification) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
-    _RS_ASSERT(rsSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(magnification) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
-    _RS_ASSERT(rsSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(wrapS) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(wrapT) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(anisotropy) == 8.0f);
-
-    if (failed) {
-        rsDebug("test_sampler_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_sampler_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void sampler_test() {
-    bool failed = false;
-    failed |= test_sampler_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/shared.rsh b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/shared.rsh
deleted file mode 100644
index b05a354..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/shared.rsh
+++ /dev/null
@@ -1,114 +0,0 @@
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_compat)
-
-typedef struct TestResult_s {
-    rs_allocation name;
-    bool pass;
-    float score;
-    int64_t time;
-} TestResult;
-//TestResult *g_results;
-
-static int64_t g_time;
-
-static void start(void) {
-    g_time = rsUptimeMillis();
-}
-
-static float end(uint32_t idx) {
-    int64_t t = rsUptimeMillis() - g_time;
-    //g_results[idx].time = t;
-    //rsDebug("test time", (int)t);
-    return ((float)t) / 1000.f;
-}
-
-#define _RS_ASSERT(b) \
-do { \
-    if (!(b)) { \
-        failed = true; \
-        rsDebug(#b " FAILED", 0); \
-    } \
-\
-} while (0)
-
-static const int iposinf = 0x7f800000;
-static const int ineginf = 0xff800000;
-
-static const float posinf() {
-    float f = *((float*)&iposinf);
-    return f;
-}
-
-static const float neginf() {
-    float f = *((float*)&ineginf);
-    return f;
-}
-
-static bool isposinf(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == iposinf);
-}
-
-static bool isneginf(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == ineginf);
-}
-
-static bool isnan(float f) {
-    int i = *((int*)(void*)&f);
-    return (((i & 0x7f800000) == 0x7f800000) && (i & 0x007fffff));
-}
-
-static bool isposzero(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == 0x00000000);
-}
-
-static bool isnegzero(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == 0x80000000);
-}
-
-static bool iszero(float f) {
-    return isposzero(f) || isnegzero(f);
-}
-
-/* Absolute epsilon used for floats.  Value is similar to float.h. */
-#ifndef FLT_EPSILON
-#define FLT_EPSILON 1.19e7f
-#endif
-/* Max ULPs while still being considered "equal".  Only used when this number
-   of ULPs is of a greater size than FLT_EPSILON. */
-#define FLT_MAX_ULP 1
-
-/* Calculate the difference in ULPs between the two values.  (Return zero on
-   perfect equality.) */
-static int float_dist(float f1, float f2) {
-    return *((int *)(&f1)) - *((int *)(&f2));
-}
-
-/* Check if two floats are essentially equal.  Will fail with some values
-   due to design.  (Validate using FLT_EPSILON or similar if necessary.) */
-static bool float_almost_equal(float f1, float f2) {
-    int *i1 = (int*)(&f1);
-    int *i2 = (int*)(&f2);
-
-    // Check for sign equality
-    if ( ((*i1 >> 31) == 0) != ((*i2 >> 31) == 0) ) {
-        // Handle signed zeroes
-        if (f1 == f2)
-            return true;
-        return false;
-    }
-
-    // Check with ULP distance
-    if (float_dist(f1, f2) > FLT_MAX_ULP)
-        return false;
-    return true;
-}
-
-/* These constants must match those in UnitTest.java */
-static const int RS_MSG_TEST_PASSED = 100;
-static const int RS_MSG_TEST_FAILED = 101;
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/struct.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/struct.rs
deleted file mode 100644
index 1cd728e..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/struct.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "shared.rsh"
-
-typedef struct Point2 {
-   int x;
-   int y;
-} Point_2;
-Point_2 *point2;
-
-static bool test_Point_2(int expected) {
-    bool failed = false;
-
-    rsDebug("Point: ", point2[0].x, point2[0].y);
-    _RS_ASSERT(point2[0].x == expected);
-    _RS_ASSERT(point2[0].y == expected);
-
-    if (failed) {
-        rsDebug("test_Point_2 FAILED", 0);
-    }
-    else {
-        rsDebug("test_Point_2 PASSED", 0);
-    }
-
-    return failed;
-}
-
-void struct_test(int expected) {
-    bool failed = false;
-    failed |= test_Point_2(expected);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/test_root.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/test_root.rs
deleted file mode 100644
index 89e7de7..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/test_root.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_compat)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-
-typedef struct TestResult {
-    rs_allocation name;
-    bool pass;
-    float score;
-} TestResult_t;
-TestResult_t *results;
-
-int root() {
-
-    return 0;
-}
-
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/unsigned.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/unsigned.rs
deleted file mode 100644
index 2c056f4..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/unsigned.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "shared.rsh"
-
-// Testing unsigned types for Bug 6764163
-unsigned int ui = 37;
-unsigned char uc = 5;
-
-static bool test_unsigned() {
-    bool failed = false;
-
-    rsDebug("ui", ui);
-    rsDebug("uc", uc);
-    _RS_ASSERT(ui == 0x7fffffff);
-    _RS_ASSERT(uc == 129);
-
-    if (failed) {
-        rsDebug("test_unsigned FAILED", -1);
-    }
-    else {
-        rsDebug("test_unsigned PASSED", 0);
-    }
-
-    return failed;
-}
-
-void unsigned_test() {
-    bool failed = false;
-    failed |= test_unsigned();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/vector.rs b/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/vector.rs
deleted file mode 100644
index 0430a2f..0000000
--- a/tests/RenderScriptTests/RSTest_CompatLib/src/com/android/rs/test/vector.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "shared.rsh"
-
-// Testing vector types
-float2 f2 = { 1.0f, 2.0f };
-float3 f3 = { 1.0f, 2.0f, 3.0f };
-float4 f4 = { 1.0f, 2.0f, 3.0f, 4.0f };
-
-double2 d2 = { 1.0, 2.0 };
-double3 d3 = { 1.0, 2.0, 3.0 };
-double4 d4 = { 1.0, 2.0, 3.0, 4.0 };
-
-char2 i8_2 = { 1, 2 };
-char3 i8_3 = { 1, 2, 3 };
-char4 i8_4 = { 1, 2, 3, 4 };
-
-uchar2 u8_2 = { 1, 2 };
-uchar3 u8_3 = { 1, 2, 3 };
-uchar4 u8_4 = { 1, 2, 3, 4 };
-
-short2 i16_2 = { 1, 2 };
-short3 i16_3 = { 1, 2, 3 };
-short4 i16_4 = { 1, 2, 3, 4 };
-
-ushort2 u16_2 = { 1, 2 };
-ushort3 u16_3 = { 1, 2, 3 };
-ushort4 u16_4 = { 1, 2, 3, 4 };
-
-int2 i32_2 = { 1, 2 };
-int3 i32_3 = { 1, 2, 3 };
-int4 i32_4 = { 1, 2, 3, 4 };
-
-uint2 u32_2 = { 1, 2 };
-uint3 u32_3 = { 1, 2, 3 };
-uint4 u32_4 = { 1, 2, 3, 4 };
-
-long2 i64_2 = { 1, 2 };
-long3 i64_3 = { 1, 2, 3 };
-long4 i64_4 = { 1, 2, 3, 4 };
-
-ulong2 u64_2 = { 1, 2 };
-ulong3 u64_3 = { 1, 2, 3 };
-ulong4 u64_4 = { 1, 2, 3, 4 };
-
-static bool test_vector_types() {
-    bool failed = false;
-
-    rsDebug("Testing F32", 0);
-    _RS_ASSERT(f2.x == 2.99f);
-    _RS_ASSERT(f2.y == 3.99f);
-
-    _RS_ASSERT(f3.x == 2.99f);
-    _RS_ASSERT(f3.y == 3.99f);
-    _RS_ASSERT(f3.z == 4.99f);
-
-    _RS_ASSERT(f4.x == 2.99f);
-    _RS_ASSERT(f4.y == 3.99f);
-    _RS_ASSERT(f4.z == 4.99f);
-    _RS_ASSERT(f4.w == 5.99f);
-
-    rsDebug("Testing F64", 0);
-    _RS_ASSERT(d2.x == 2.99);
-    _RS_ASSERT(d2.y == 3.99);
-
-    _RS_ASSERT(d3.x == 2.99);
-    _RS_ASSERT(d3.y == 3.99);
-    _RS_ASSERT(d3.z == 4.99);
-
-    _RS_ASSERT(d4.x == 2.99);
-    _RS_ASSERT(d4.y == 3.99);
-    _RS_ASSERT(d4.z == 4.99);
-    _RS_ASSERT(d4.w == 5.99);
-
-    rsDebug("Testing I8", 0);
-    _RS_ASSERT(i8_2.x == 2);
-    _RS_ASSERT(i8_2.y == 3);
-
-    _RS_ASSERT(i8_3.x == 2);
-    _RS_ASSERT(i8_3.y == 3);
-    _RS_ASSERT(i8_3.z == 4);
-
-    _RS_ASSERT(i8_4.x == 2);
-    _RS_ASSERT(i8_4.y == 3);
-    _RS_ASSERT(i8_4.z == 4);
-    _RS_ASSERT(i8_4.w == 5);
-
-    rsDebug("Testing U8", 0);
-    _RS_ASSERT(u8_2.x == 2);
-    _RS_ASSERT(u8_2.y == 3);
-
-    _RS_ASSERT(u8_3.x == 2);
-    _RS_ASSERT(u8_3.y == 3);
-    _RS_ASSERT(u8_3.z == 4);
-
-    _RS_ASSERT(u8_4.x == 2);
-    _RS_ASSERT(u8_4.y == 3);
-    _RS_ASSERT(u8_4.z == 4);
-    _RS_ASSERT(u8_4.w == 5);
-
-    rsDebug("Testing I16", 0);
-    _RS_ASSERT(i16_2.x == 2);
-    _RS_ASSERT(i16_2.y == 3);
-
-    _RS_ASSERT(i16_3.x == 2);
-    _RS_ASSERT(i16_3.y == 3);
-    _RS_ASSERT(i16_3.z == 4);
-
-    _RS_ASSERT(i16_4.x == 2);
-    _RS_ASSERT(i16_4.y == 3);
-    _RS_ASSERT(i16_4.z == 4);
-    _RS_ASSERT(i16_4.w == 5);
-
-    rsDebug("Testing U16", 0);
-    _RS_ASSERT(u16_2.x == 2);
-    _RS_ASSERT(u16_2.y == 3);
-
-    _RS_ASSERT(u16_3.x == 2);
-    _RS_ASSERT(u16_3.y == 3);
-    _RS_ASSERT(u16_3.z == 4);
-
-    _RS_ASSERT(u16_4.x == 2);
-    _RS_ASSERT(u16_4.y == 3);
-    _RS_ASSERT(u16_4.z == 4);
-    _RS_ASSERT(u16_4.w == 5);
-
-    rsDebug("Testing I32", 0);
-    _RS_ASSERT(i32_2.x == 2);
-    _RS_ASSERT(i32_2.y == 3);
-
-    _RS_ASSERT(i32_3.x == 2);
-    _RS_ASSERT(i32_3.y == 3);
-    _RS_ASSERT(i32_3.z == 4);
-
-    _RS_ASSERT(i32_4.x == 2);
-    _RS_ASSERT(i32_4.y == 3);
-    _RS_ASSERT(i32_4.z == 4);
-    _RS_ASSERT(i32_4.w == 5);
-
-    rsDebug("Testing U32", 0);
-    _RS_ASSERT(u32_2.x == 2);
-    _RS_ASSERT(u32_2.y == 3);
-
-    _RS_ASSERT(u32_3.x == 2);
-    _RS_ASSERT(u32_3.y == 3);
-    _RS_ASSERT(u32_3.z == 4);
-
-    _RS_ASSERT(u32_4.x == 2);
-    _RS_ASSERT(u32_4.y == 3);
-    _RS_ASSERT(u32_4.z == 4);
-    _RS_ASSERT(u32_4.w == 5);
-
-    rsDebug("Testing I64", 0);
-    _RS_ASSERT(i64_2.x == 2);
-    _RS_ASSERT(i64_2.y == 3);
-
-    _RS_ASSERT(i64_3.x == 2);
-    _RS_ASSERT(i64_3.y == 3);
-    _RS_ASSERT(i64_3.z == 4);
-
-    _RS_ASSERT(i64_4.x == 2);
-    _RS_ASSERT(i64_4.y == 3);
-    _RS_ASSERT(i64_4.z == 4);
-    _RS_ASSERT(i64_4.w == 5);
-
-    rsDebug("Testing U64", 0);
-    _RS_ASSERT(u64_2.x == 2);
-    _RS_ASSERT(u64_2.y == 3);
-
-    _RS_ASSERT(u64_3.x == 2);
-    _RS_ASSERT(u64_3.y == 3);
-    _RS_ASSERT(u64_3.z == 4);
-
-    _RS_ASSERT(u64_4.x == 2);
-    _RS_ASSERT(u64_4.y == 3);
-    _RS_ASSERT(u64_4.z == 4);
-    _RS_ASSERT(u64_4.w == 5);
-
-    if (failed) {
-        rsDebug("test_vector FAILED", 0);
-    }
-    else {
-        rsDebug("test_vector PASSED", 0);
-    }
-
-    return failed;
-}
-
-void vector_test() {
-    bool failed = false;
-    failed |= test_vector_types();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/SampleTest/Android.mk b/tests/RenderScriptTests/SampleTest/Android.mk
deleted file mode 100644
index f3439b0..0000000
--- a/tests/RenderScriptTests/SampleTest/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := SampleRS
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SampleTest/AndroidManifest.xml b/tests/RenderScriptTests/SampleTest/AndroidManifest.xml
deleted file mode 100644
index ec115f7..0000000
--- a/tests/RenderScriptTests/SampleTest/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +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.
-*/
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.sample">
-    <uses-sdk android:minSdkVersion="14" />
-    <application android:label="Sample Test"
-                 android:hardwareAccelerated="true">
-
-        <activity android:name="SampleRSActivity"
-                  android:label="Sample Test">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/SampleTest/res/drawable-nodpi/city.png b/tests/RenderScriptTests/SampleTest/res/drawable-nodpi/city.png
deleted file mode 100644
index 27c4618..0000000
--- a/tests/RenderScriptTests/SampleTest/res/drawable-nodpi/city.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SampleTest/res/drawable-nodpi/twobytwo.png b/tests/RenderScriptTests/SampleTest/res/drawable-nodpi/twobytwo.png
deleted file mode 100644
index 98cf963..0000000
--- a/tests/RenderScriptTests/SampleTest/res/drawable-nodpi/twobytwo.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/SampleTest/res/layout/rs.xml b/tests/RenderScriptTests/SampleTest/res/layout/rs.xml
deleted file mode 100644
index f2a356f..0000000
--- a/tests/RenderScriptTests/SampleTest/res/layout/rs.xml
+++ /dev/null
@@ -1,84 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-            android:orientation="vertical"
-            android:layout_width="fill_parent"
-            android:layout_height="fill_parent"
-            android:id="@+id/toplevel">
-    <ScrollView
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent">
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="vertical"
-                android:layout_width="fill_parent"
-                android:layout_height="fill_parent">
-            <TextView
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/wraplinear"/>
-            <TextureView
-                android:id="@+id/display"
-                android:layout_width="256sp"
-                android:layout_height="256sp" />
-            <TextView
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/clamplinear"/>
-            <TextureView
-                android:id="@+id/display2"
-                android:layout_width="256sp"
-                android:layout_height="256sp" />
-            <TextView
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/wrapnearest"/>
-            <TextureView
-                android:id="@+id/display3"
-                android:layout_width="256sp"
-                android:layout_height="256sp" />
-            <TextView
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/clampnearest"/>
-            <TextureView
-                android:id="@+id/display4"
-                android:layout_width="256sp"
-                android:layout_height="256sp" />
-            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content">
-                    <Button
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="@string/benchmark"
-                        android:onClick="benchmark"/>
-                    <TextView
-                        android:id="@+id/benchmarkText"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:textSize="8pt"
-                        android:text="@string/benchmark"/>
-            </LinearLayout>
-            </LinearLayout>
-    </ScrollView>
-</LinearLayout>
-
diff --git a/tests/RenderScriptTests/SampleTest/res/values/strings.xml b/tests/RenderScriptTests/SampleTest/res/values/strings.xml
deleted file mode 100644
index a0a2499..0000000
--- a/tests/RenderScriptTests/SampleTest/res/values/strings.xml
+++ /dev/null
@@ -1,28 +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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- General -->
-    <skip />
-    <string name="benchmark">Benchmark</string>
-    <string name="wraplinear">Wrap Linear</string>
-    <string name="clamplinear">Clamp Linear</string>
-    <string name="wrapnearest">Wrap Nearest</string>
-    <string name="clampnearest">Clamp Nearest</string>
-</resources>
diff --git a/tests/RenderScriptTests/SampleTest/src/com/android/rs/sample/SampleRSActivity.java b/tests/RenderScriptTests/SampleTest/src/com/android/rs/sample/SampleRSActivity.java
deleted file mode 100644
index 77cbf84..0000000
--- a/tests/RenderScriptTests/SampleTest/src/com/android/rs/sample/SampleRSActivity.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.sample;
-
-import android.app.Activity;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.SurfaceTexture;
-import android.os.Bundle;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Matrix3f;
-import android.renderscript.RenderScript;
-import android.renderscript.Sampler;
-import android.renderscript.Type;
-import android.renderscript.Type.Builder;
-import android.util.Log;
-import android.view.TextureView;
-import android.view.TextureView.SurfaceTextureListener;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-public class SampleRSActivity extends Activity {
-    class TextureViewUpdater implements TextureView.SurfaceTextureListener {
-        private Allocation mOutPixelsAllocation;
-        private Sampler mSampler;
-
-        TextureViewUpdater(Allocation outAlloc, Sampler sampler) {
-            mOutPixelsAllocation = outAlloc;
-            mSampler = sampler;
-        }
-
-        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
-        }
-
-        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
-            mOutPixelsAllocation.setSurfaceTexture(surface);
-        }
-
-        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
-            mOutPixelsAllocation.setSurfaceTexture(surface);
-            filterAlloc(mOutPixelsAllocation, mSampler);
-        }
-
-        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-            mOutPixelsAllocation.setSurfaceTexture(null);
-            return true;
-        }
-    }
-
-    private final String TAG = "Img";
-    private Bitmap mBitmapTwoByTwo;
-    private Bitmap mBitmapCity;
-
-    private TextView mBenchmarkResult;
-
-    private RenderScript mRS;
-    private Allocation mTwoByTwoAlloc;
-    private Allocation mCityAlloc;
-    private ScriptC_sample mScript;
-
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    public void onStopTrackingTouch(SeekBar seekBar) {
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.rs);
-
-        mBitmapTwoByTwo = loadBitmap(R.drawable.twobytwo);
-        mBitmapCity = loadBitmap(R.drawable.city);
-
-        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
-        mBenchmarkResult.setText("Result: not run");
-
-        mRS = RenderScript.create(this);
-        mTwoByTwoAlloc = Allocation.createFromBitmap(mRS, mBitmapTwoByTwo,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-
-        mCityAlloc = Allocation.createFromBitmap(mRS, mBitmapCity,
-                                                          Allocation.MipmapControl.MIPMAP_NONE,
-                                                          Allocation.USAGE_SCRIPT);
-
-        Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-
-        int usage = Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT;
-
-        int outX = 256;
-        int outY = 256;
-
-        // Wrap Linear
-        Allocation outAlloc = Allocation.createTyped(mRS, b.setX(outX).setY(outY).create(), usage);
-        TextureViewUpdater updater = new TextureViewUpdater(outAlloc, Sampler.WRAP_LINEAR(mRS));
-        TextureView displayView = (TextureView) findViewById(R.id.display);
-        displayView.setSurfaceTextureListener(updater);
-
-        // Clamp Linear
-        outAlloc = Allocation.createTyped(mRS, b.setX(outX).setY(outY).create(), usage);
-        updater = new TextureViewUpdater(outAlloc, Sampler.CLAMP_LINEAR(mRS));
-        displayView = (TextureView) findViewById(R.id.display2);
-        displayView.setSurfaceTextureListener(updater);
-
-        // Wrap Nearest
-        outAlloc = Allocation.createTyped(mRS, b.setX(outX).setY(outY).create(), usage);
-        updater = new TextureViewUpdater(outAlloc, Sampler.WRAP_NEAREST(mRS));
-        displayView = (TextureView) findViewById(R.id.display3);
-        displayView.setSurfaceTextureListener(updater);
-
-        // Clamp Nearest
-        outAlloc = Allocation.createTyped(mRS, b.setX(outX).setY(outY).create(), usage);
-        updater = new TextureViewUpdater(outAlloc, Sampler.CLAMP_NEAREST(mRS));
-        displayView = (TextureView) findViewById(R.id.display4);
-        displayView.setSurfaceTextureListener(updater);
-
-        mScript = new ScriptC_sample(mRS, getResources(), R.raw.sample);
-    }
-
-    private Bitmap loadBitmap(int resource) {
-        final BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-        Bitmap b = BitmapFactory.decodeResource(getResources(), resource, options);
-        Bitmap b2 = Bitmap.createBitmap(b.getWidth(), b.getHeight(), b.getConfig());
-        Canvas c = new Canvas(b2);
-        c.drawBitmap(b, 0, 0, null);
-        b.recycle();
-        return b2;
-    }
-
-    private synchronized void filterAlloc(Allocation alloc, Sampler sampler) {
-        long t = java.lang.System.currentTimeMillis();
-        mScript.invoke_setSampleData(alloc, mTwoByTwoAlloc, sampler);
-        mScript.forEach_root(alloc);
-        alloc.ioSendOutput();
-        mRS.finish();
-        t = java.lang.System.currentTimeMillis() - t;
-        Log.i(TAG, "Filter time is: " + t + " ms");
-    }
-
-    public void benchmark(View v) {
-        /*filterAlloc();
-        long t = java.lang.System.currentTimeMillis();
-        filterAlloc();
-        t = java.lang.System.currentTimeMillis() - t;
-        mDisplayView.invalidate();
-        mBenchmarkResult.setText("Result: " + t + " ms");*/
-    }
-}
diff --git a/tests/RenderScriptTests/SampleTest/src/com/android/rs/sample/sample.rs b/tests/RenderScriptTests/SampleTest/src/com/android/rs/sample/sample.rs
deleted file mode 100644
index e2bf43d..0000000
--- a/tests/RenderScriptTests/SampleTest/src/com/android/rs/sample/sample.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-#pragma version(1)
-#pragma rs java_package_name(com.android.rs.sample)
-#include "rs_graphics.rsh"
-
-static rs_allocation sourceAlloc;
-static rs_allocation destAlloc;
-static rs_sampler allocSampler;
-
-void setSampleData(rs_allocation dest, rs_allocation source, rs_sampler sampler) {
-    destAlloc = dest;
-    sourceAlloc = source;
-    allocSampler = sampler;
-}
-
-void root(uchar4 *out, uint32_t x, uint32_t y) {
-
-    float destX = (float)rsAllocationGetDimX(destAlloc) - 1.0f;
-    float destY = (float)rsAllocationGetDimY(destAlloc) - 1.0f;
-
-    float2 uv;
-    uv.x = (float)x / destX;
-    uv.y = (float)y / destY;
-
-    out->xyz = convert_uchar3(rsSample(sourceAlloc, allocSampler, uv*2.0f).xyz);
-    out->w = 0xff;
-}
-
diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk
index 163a95d..6047305 100644
--- a/tests/RenderScriptTests/SceneGraph/Android.mk
+++ b/tests/RenderScriptTests/SceneGraph/Android.mk
@@ -21,6 +21,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
+LOCAL_SDK_VERSION := 17
+
 LOCAL_PACKAGE_NAME := SceneGraphTest
 
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ShadersTest/Android.mk b/tests/RenderScriptTests/ShadersTest/Android.mk
index 0912591..fb6356e 100644
--- a/tests/RenderScriptTests/ShadersTest/Android.mk
+++ b/tests/RenderScriptTests/ShadersTest/Android.mk
@@ -21,6 +21,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
+LOCAL_SDK_VERSION := 17
+
 LOCAL_PACKAGE_NAME := ShadersTest
 
 include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/tests/Android.mk b/tests/RenderScriptTests/tests/Android.mk
deleted file mode 100644
index 198693c..0000000
--- a/tests/RenderScriptTests/tests/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RSTest
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/tests/AndroidManifest.xml b/tests/RenderScriptTests/tests/AndroidManifest.xml
deleted file mode 100644
index b660398..0000000
--- a/tests/RenderScriptTests/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.test">
-    <application 
-        android:label="_RS_Test"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="RSTest"
-                  android:screenOrientation="portrait">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/tests/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/tests/res/drawable-nodpi/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/tests/res/drawable-nodpi/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTest.java
deleted file mode 100644
index d1b23fa..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import java.lang.Runtime;
-
-public class RSTest extends Activity {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "RSTest";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private RSTestView mView;
-
-    // get the current looper (from your Activity UI thread for instance
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RSTestView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onPause();
-        mView.pause();
-    }
-
-    @Override
-    protected void onStop() {
-        // Actually kill the app if we are stopping. We don't want to
-        // continue/resume this test ever. It should always start fresh.
-        finish();
-        super.onStop();
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
deleted file mode 100644
index 8645ae5..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2008-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.ListIterator;
-import java.util.Timer;
-import java.util.TimerTask;
-
-
-public class RSTestCore {
-    int mWidth;
-    int mHeight;
-    Context mCtx;
-
-    public RSTestCore(Context ctx) {
-        mCtx = ctx;
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    private Font mFont;
-    ScriptField_ListAllocs_s mListAllocs;
-    int mLastX;
-    int mLastY;
-    private ScriptC_rslist mScript;
-
-    private ArrayList<UnitTest> unitTests;
-    private ListIterator<UnitTest> test_iter;
-    private UnitTest activeTest;
-    private boolean stopTesting;
-
-    /* Periodic timer for ensuring future tests get scheduled */
-    private Timer mTimer;
-    public static final int RS_TIMER_PERIOD = 100;
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-        stopTesting = false;
-
-        mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist);
-
-        unitTests = new ArrayList<UnitTest>();
-
-        unitTests.add(new UT_primitives(this, mRes, mCtx));
-        unitTests.add(new UT_constant(this, mRes, mCtx));
-        unitTests.add(new UT_vector(this, mRes, mCtx));
-        unitTests.add(new UT_unsigned(this, mRes, mCtx));
-        unitTests.add(new UT_array_init(this, mRes, mCtx));
-        unitTests.add(new UT_array_alloc(this, mRes, mCtx));
-        unitTests.add(new UT_kernel(this, mRes, mCtx));
-        unitTests.add(new UT_kernel_struct(this, mRes, mCtx));
-        unitTests.add(new UT_bug_char(this, mRes, mCtx));
-        unitTests.add(new UT_clamp(this, mRes, mCtx));
-        unitTests.add(new UT_clamp_relaxed(this, mRes, mCtx));
-        unitTests.add(new UT_convert(this, mRes, mCtx));
-        unitTests.add(new UT_convert_relaxed(this, mRes, mCtx));
-        unitTests.add(new UT_copy_test(this, mRes, mCtx));
-        unitTests.add(new UT_rsdebug(this, mRes, mCtx));
-        unitTests.add(new UT_rstime(this, mRes, mCtx));
-        unitTests.add(new UT_rstypes(this, mRes, mCtx));
-        unitTests.add(new UT_alloc(this, mRes, mCtx));
-        unitTests.add(new UT_refcount(this, mRes, mCtx));
-        unitTests.add(new UT_foreach(this, mRes, mCtx));
-        unitTests.add(new UT_foreach_bounds(this, mRes, mCtx));
-        unitTests.add(new UT_noroot(this, mRes, mCtx));
-        unitTests.add(new UT_atomic(this, mRes, mCtx));
-        unitTests.add(new UT_struct(this, mRes, mCtx));
-        unitTests.add(new UT_math(this, mRes, mCtx));
-        unitTests.add(new UT_math_conformance(this, mRes, mCtx));
-        unitTests.add(new UT_math_agree(this, mRes, mCtx));
-        unitTests.add(new UT_min(this, mRes, mCtx));
-        unitTests.add(new UT_int4(this, mRes, mCtx));
-        unitTests.add(new UT_element(this, mRes, mCtx));
-        unitTests.add(new UT_sampler(this, mRes, mCtx));
-        unitTests.add(new UT_program_store(this, mRes, mCtx));
-        unitTests.add(new UT_program_raster(this, mRes, mCtx));
-        unitTests.add(new UT_mesh(this, mRes, mCtx));
-        unitTests.add(new UT_fp_mad(this, mRes, mCtx));
-
-        /*
-        unitTests.add(new UnitTest(null, "<Pass>", 1));
-        unitTests.add(new UnitTest());
-        unitTests.add(new UnitTest(null, "<Fail>", -1));
-
-        for (int i = 0; i < 20; i++) {
-            unitTests.add(new UnitTest(null, "<Pass>", 1));
-        }
-        */
-
-        UnitTest [] uta = new UnitTest[unitTests.size()];
-        uta = unitTests.toArray(uta);
-
-        mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length);
-        for (int i = 0; i < uta.length; i++) {
-            ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
-            listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
-            listElem.result = uta[i].getResult();
-            mListAllocs.set(listElem, i, false);
-            uta[i].setItem(listElem);
-        }
-
-        mListAllocs.copyAll();
-
-        mScript.bind_gList(mListAllocs);
-
-        mFont = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8);
-        mScript.set_gFont(mFont);
-
-        mRS.bindRootScript(mScript);
-
-        test_iter = unitTests.listIterator();
-        refreshTestResults(); /* Kick off the first test */
-
-        TimerTask pTask = new TimerTask() {
-            public void run() {
-                refreshTestResults();
-            }
-        };
-
-        mTimer = new Timer();
-        mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD);
-    }
-
-    public void checkAndRunNextTest() {
-        if (activeTest != null) {
-            if (!activeTest.isAlive()) {
-                /* Properly clean up on our last test */
-                try {
-                    activeTest.join();
-                }
-                catch (InterruptedException e) {
-                }
-                activeTest = null;
-            }
-        }
-
-        if (!stopTesting && activeTest == null) {
-            if (test_iter.hasNext()) {
-                activeTest = test_iter.next();
-                activeTest.start();
-                /* This routine will only get called once when a new test
-                 * should start running. The message handler in UnitTest.java
-                 * ensures this. */
-            }
-            else {
-                if (mTimer != null) {
-                    mTimer.cancel();
-                    mTimer.purge();
-                    mTimer = null;
-                }
-            }
-        }
-    }
-
-    public void refreshTestResults() {
-        checkAndRunNextTest();
-
-        if (mListAllocs != null && mScript != null && mRS != null) {
-            mListAllocs.copyAll();
-
-            mScript.bind_gList(mListAllocs);
-            mRS.bindRootScript(mScript);
-        }
-    }
-
-    public void cleanup() {
-        stopTesting = true;
-        UnitTest t = activeTest;
-
-        /* Stop periodic refresh of testing */
-        if (mTimer != null) {
-            mTimer.cancel();
-            mTimer.purge();
-            mTimer = null;
-        }
-
-        /* Wait to exit until we finish the current test */
-        if (t != null) {
-            try {
-                t.join();
-            }
-            catch (InterruptedException e) {
-            }
-            t = null;
-        }
-
-    }
-
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-    }
-
-    public void onActionDown(int x, int y) {
-        mScript.set_gDY(0.0f);
-        mLastX = x;
-        mLastY = y;
-        refreshTestResults();
-    }
-
-    public void onActionMove(int x, int y) {
-        int dx = mLastX - x;
-        int dy = mLastY - y;
-
-        if (Math.abs(dy) <= 2) {
-            dy = 0;
-        }
-
-        mScript.set_gDY(dy);
-
-        mLastX = x;
-        mLastY = y;
-        refreshTestResults();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestView.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestView.java
deleted file mode 100644
index 368f286..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestView.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class RSTestView extends RSSurfaceView {
-
-    private Context mCtx;
-
-    public RSTestView(Context context) {
-        super(context);
-        mCtx = context;
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private RSTestCore mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new RSTestCore(mCtx);
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if(mRS != null) {
-            mRender.cleanup();
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event)
-    {
-        return super.onKeyDown(keyCode, event);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        boolean ret = false;
-        int act = ev.getAction();
-        if (act == ev.ACTION_DOWN) {
-            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-        else if (act == ev.ACTION_MOVE) {
-            mRender.onActionMove((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-
-        return ret;
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
deleted file mode 100644
index 3ea942c..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_alloc.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_alloc extends UnitTest {
-    private Resources mRes;
-
-    protected UT_alloc(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Alloc", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_alloc s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        int Z = 0;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        s.set_dimZ(Z);
-        typeBuilder.setX(X).setY(Y);
-        Allocation A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
-        s.set_aRaw(A);
-
-        typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        typeBuilder.setX(X).setY(Y).setFaces(true);
-        Allocation AFaces = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aFaces(AFaces);
-        typeBuilder.setFaces(false).setMipmaps(true);
-        Allocation ALOD = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aLOD(ALOD);
-        typeBuilder.setFaces(true).setMipmaps(true);
-        Allocation AFacesLOD = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aFacesLOD(AFacesLOD);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_alloc s = new ScriptC_alloc(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_root(s.get_aRaw());
-        s.invoke_alloc_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_alloc.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_alloc.java
deleted file mode 100644
index ac01a93..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_alloc.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_array_alloc extends UnitTest {
-    private Resources mRes;
-
-    protected UT_array_alloc(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Array Allocation", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_array_alloc s = new ScriptC_array_alloc(pRS);
-        pRS.setMessageHandler(mRsMessage);
-
-        int dimX = s.get_dimX();
-        Allocation[] Arr = new Allocation[dimX];
-        Type.Builder typeBuilder = new Type.Builder(pRS, Element.I32(pRS));
-        Type T = typeBuilder.setX(1).create();
-        for (int i = 0; i < dimX; i++) {
-            Allocation A = Allocation.createTyped(pRS, T);
-            Arr[i] = A;
-        }
-        s.set_a(Arr);
-
-        s.invoke_array_alloc_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
deleted file mode 100644
index c74e4b3..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_array_init extends UnitTest {
-    private Resources mRes;
-
-    protected UT_array_init(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Array Init", ctx);
-        mRes = res;
-    }
-
-    private void checkInit(ScriptC_array_init s) {
-        float[] fa = s.get_fa();
-        _RS_ASSERT("fa[0] == 1.0", fa[0] == 1.0);
-        _RS_ASSERT("fa[1] == 9.9999f", fa[1] == 9.9999f);
-        _RS_ASSERT("fa[2] == 0", fa[2] == 0);
-        _RS_ASSERT("fa[3] == 0", fa[3] == 0);
-        _RS_ASSERT("fa.length == 4", fa.length == 4);
-
-        double[] da = s.get_da();
-        _RS_ASSERT("da[0] == 7.0", da[0] == 7.0);
-        _RS_ASSERT("da[1] == 8.88888", da[1] == 8.88888);
-        _RS_ASSERT("da.length == 2", da.length == 2);
-
-        byte[] ca = s.get_ca();
-        _RS_ASSERT("ca[0] == 'a'", ca[0] == 'a');
-        _RS_ASSERT("ca[1] == 7", ca[1] == 7);
-        _RS_ASSERT("ca[2] == 'b'", ca[2] == 'b');
-        _RS_ASSERT("ca[3] == 'c'", ca[3] == 'c');
-        _RS_ASSERT("ca.length == 4", ca.length == 4);
-
-        short[] sa = s.get_sa();
-        _RS_ASSERT("sa[0] == 1", sa[0] == 1);
-        _RS_ASSERT("sa[1] == 1", sa[1] == 1);
-        _RS_ASSERT("sa[2] == 2", sa[2] == 2);
-        _RS_ASSERT("sa[3] == 3", sa[3] == 3);
-        _RS_ASSERT("sa.length == 4", sa.length == 4);
-
-        int[] ia = s.get_ia();
-        _RS_ASSERT("ia[0] == 5", ia[0] == 5);
-        _RS_ASSERT("ia[1] == 8", ia[1] == 8);
-        _RS_ASSERT("ia[2] == 0", ia[2] == 0);
-        _RS_ASSERT("ia[3] == 0", ia[3] == 0);
-        _RS_ASSERT("ia.length == 4", ia.length == 4);
-
-        long[] la = s.get_la();
-        _RS_ASSERT("la[0] == 13", la[0] == 13);
-        _RS_ASSERT("la[1] == 21", la[1] == 21);
-        _RS_ASSERT("la.length == 4", la.length == 2);
-
-        long[] lla = s.get_lla();
-        _RS_ASSERT("lla[0] == 34", lla[0] == 34);
-        _RS_ASSERT("lla[1] == 0", lla[1] == 0);
-        _RS_ASSERT("lla[2] == 0", lla[2] == 0);
-        _RS_ASSERT("lla[3] == 0", lla[3] == 0);
-        _RS_ASSERT("lla.length == 4", lla.length == 4);
-
-        boolean[] ba = s.get_ba();
-        _RS_ASSERT("ba[0] == true", ba[0] == true);
-        _RS_ASSERT("ba[1] == false", ba[1] == false);
-        _RS_ASSERT("ba[2] == false", ba[2] == false);
-        _RS_ASSERT("ba.length == 3", ba.length == 3);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_array_init s = new ScriptC_array_init(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        checkInit(s);
-        s.invoke_array_init_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java
deleted file mode 100644
index 0b8e072..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_atomic extends UnitTest {
-    private Resources mRes;
-
-    protected UT_atomic(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Atomics", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_atomic s = new ScriptC_atomic(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_atomic_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_bug_char.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_bug_char.java
deleted file mode 100644
index faf3a31..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_bug_char.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-import java.util.Arrays;
-
-public class UT_bug_char extends UnitTest {
-    private Resources mRes;
-
-    protected UT_bug_char(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Bug Char", ctx);
-        mRes = res;
-    }
-
-    // packing functions
-    private Byte2 pack_b2(byte[] val) {
-        assert val.length == 2;
-        Log.i("bug_char", "pack_b2 " + val[0] + " " + val[1]);
-        return new Byte2(val[0], val[1]);
-    }
-
-    private byte min(byte v1, byte v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private byte[] min(byte[] v1, byte[] v2) {
-        assert v1.length == v2.length;
-        byte[] rv = new byte[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-
-    private void initializeValues(ScriptC_bug_char s) {
-        byte rand_sc1_0 = (byte)7;
-        byte[] rand_sc2_0 = new byte[2];
-        rand_sc2_0[0] = 11;
-        rand_sc2_0[1] = 21;
-        Log.i("bug_char", "Generated sc2_0 to " + Arrays.toString(rand_sc2_0));
-        byte rand_sc1_1 = (byte)10;
-        byte[] rand_sc2_1 = new byte[2];
-        rand_sc2_1[0] = 13;
-        rand_sc2_1[1] = 15;
-        Log.i("bug_char", "Generated sc2_1 to " + Arrays.toString(rand_sc2_1));
-
-        s.set_rand_sc1_0(rand_sc1_0);
-        s.set_rand_sc2_0(pack_b2(rand_sc2_0));
-        s.set_rand_sc1_1(rand_sc1_1);
-        s.set_rand_sc2_1(pack_b2(rand_sc2_1));
-        // Set results for min
-        s.set_min_rand_sc1_sc1(min(rand_sc1_0, rand_sc1_1));
-        byte[] min_rand_sc2_raw = min(rand_sc2_0, rand_sc2_1);
-        Log.i("bug_char", "Generating min_rand_sc2_sc2 to " +
-              Arrays.toString(min_rand_sc2_raw));
-        Byte2 min_rand_sc2 = pack_b2(min_rand_sc2_raw);
-        Log.i("bug_char", "Setting min_rand_sc2_sc2 to [" + min_rand_sc2.x +
-              ", " + min_rand_sc2.y + "]");
-        s.set_min_rand_sc2_sc2(min_rand_sc2);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_bug_char s = new ScriptC_bug_char(pRS, mRes,
-                R.raw.bug_char);
-        pRS.setMessageHandler(mRsMessage);
-        initializeValues(s);
-        s.invoke_bug_char_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_clamp.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_clamp.java
deleted file mode 100644
index de98d0c..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_clamp.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_clamp extends UnitTest {
-    private Resources mRes;
-
-    protected UT_clamp(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Clamp (Full)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_clamp s = new ScriptC_clamp(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_clamp_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_clamp_relaxed.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_clamp_relaxed.java
deleted file mode 100644
index 91e7140..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_clamp_relaxed.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_clamp_relaxed extends UnitTest {
-    private Resources mRes;
-
-    protected UT_clamp_relaxed(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Clamp (Relaxed)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_clamp_relaxed s =
-                new ScriptC_clamp_relaxed(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_clamp_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
deleted file mode 100644
index adda5a3..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_constant extends UnitTest {
-    private Resources mRes;
-
-    protected UT_constant(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Const", ctx);
-        mRes = res;
-    }
-
-    private void Assert(boolean b) {
-        if (!b) {
-            failTest();
-        }
-    }
-
-    public void run() {
-        Assert(ScriptC_constant.const_floatTest == 1.99f);
-        Assert(ScriptC_constant.const_doubleTest == 2.05);
-        Assert(ScriptC_constant.const_charTest == -8);
-        Assert(ScriptC_constant.const_shortTest == -16);
-        Assert(ScriptC_constant.const_intTest == -32);
-        Assert(ScriptC_constant.const_longTest == 17179869184l);
-        Assert(ScriptC_constant.const_longlongTest == 68719476736l);
-
-        Assert(ScriptC_constant.const_ucharTest == 8);
-        Assert(ScriptC_constant.const_ushortTest == 16);
-        Assert(ScriptC_constant.const_uintTest == 32);
-        Assert(ScriptC_constant.const_ulongTest == 4611686018427387904L);
-        Assert(ScriptC_constant.const_int64_tTest == -17179869184l);
-        Assert(ScriptC_constant.const_uint64_tTest == 117179869184l);
-
-        Assert(ScriptC_constant.const_boolTest == true);
-
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert.java
deleted file mode 100644
index adf79bc..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_convert extends UnitTest {
-    private Resources mRes;
-
-    protected UT_convert(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Convert", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_convert s = new ScriptC_convert(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_convert_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert_relaxed.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert_relaxed.java
deleted file mode 100644
index a0757f3..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_convert_relaxed.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_convert_relaxed extends UnitTest {
-    private Resources mRes;
-
-    protected UT_convert_relaxed(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Convert (Relaxed)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_convert_relaxed s =
-                new ScriptC_convert_relaxed(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_convert_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_copy_test.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_copy_test.java
deleted file mode 100644
index 380f6ec..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_copy_test.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-public class UT_copy_test extends UnitTest {
-    private Resources mRes;
-    boolean pass = true;
-
-    protected UT_copy_test(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Copy", ctx);
-        mRes = res;
-    }
-
-    void testFloat2(RenderScript rs, ScriptC_copy_test s) {
-        Allocation a1 = Allocation.createSized(rs, Element.F32_2(rs), 1024);
-        Allocation a2 = Allocation.createSized(rs, Element.F32_2(rs), 1024);
-
-        float[] f1 = new float[1024 * 2];
-        float[] f2 = new float[1024 * 2];
-        for (int ct=0; ct < f1.length; ct++) {
-            f1[ct] = (float)ct;
-        }
-        a1.copyFrom(f1);
-
-        s.forEach_copyFloat2(a1, a2);
-
-        a2.copyTo(f2);
-        for (int ct=0; ct < f1.length; ct++) {
-            if (f1[ct] != f2[ct]) {
-                failTest();
-                Log.v("RS Test", "Compare failed at " + ct + ", " + f1[ct] + ", " + f2[ct]);
-            }
-        }
-        a1.destroy();
-        a2.destroy();
-    }
-
-    void testFloat3(RenderScript rs, ScriptC_copy_test s) {
-        Allocation a1 = Allocation.createSized(rs, Element.F32_3(rs), 1024);
-        Allocation a2 = Allocation.createSized(rs, Element.F32_3(rs), 1024);
-
-        float[] f1 = new float[1024 * 4];
-        float[] f2 = new float[1024 * 4];
-        for (int ct=0; ct < f1.length; ct++) {
-            f1[ct] = (float)ct;
-        }
-        a1.copyFrom(f1);
-
-        s.forEach_copyFloat3(a1, a2);
-
-        a2.copyTo(f2);
-        for (int ct=0; ct < f1.length; ct++) {
-            if ((f1[ct] != f2[ct]) && ((ct&3) != 3)) {
-                failTest();
-                Log.v("RS Test", "Compare failed at " + ct + ", " + f1[ct] + ", " + f2[ct]);
-            }
-        }
-        a1.destroy();
-        a2.destroy();
-    }
-
-    void testFloat4(RenderScript rs, ScriptC_copy_test s) {
-        Allocation a1 = Allocation.createSized(rs, Element.F32_4(rs), 1024);
-        Allocation a2 = Allocation.createSized(rs, Element.F32_4(rs), 1024);
-
-        float[] f1 = new float[1024 * 4];
-        float[] f2 = new float[1024 * 4];
-        for (int ct=0; ct < f1.length; ct++) {
-            f1[ct] = (float)ct;
-        }
-        a1.copyFrom(f1);
-
-        s.forEach_copyFloat4(a1, a2);
-
-        a2.copyTo(f2);
-        for (int ct=0; ct < f1.length; ct++) {
-            if (f1[ct] != f2[ct]) {
-                failTest();
-                Log.v("RS Test", "Compare failed at " + ct + ", " + f1[ct] + ", " + f2[ct]);
-            }
-        }
-        a1.destroy();
-        a2.destroy();
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_copy_test s = new ScriptC_copy_test(pRS);
-        pRS.setMessageHandler(mRsMessage);
-
-        testFloat2(pRS, s);
-        testFloat3(pRS, s);
-        testFloat4(pRS, s);
-        s.invoke_sendResult(true);
-
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
deleted file mode 100644
index 07bcc74..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Element.*;
-import android.renderscript.Element.DataKind.*;
-import android.renderscript.Element.DataType.*;
-
-public class UT_element extends UnitTest {
-    private Resources mRes;
-
-    Element simpleElem;
-    Element complexElem;
-
-    final String subElemNames[] = {
-        "subElem0",
-        "subElem1",
-        "subElem2",
-        "arrayElem0",
-        "arrayElem1",
-        "subElem3",
-        "subElem4",
-        "subElem5",
-        "subElem6",
-        "subElem_7",
-    };
-
-    final int subElemArraySizes[] = {
-        1,
-        1,
-        1,
-        2,
-        5,
-        1,
-        1,
-        1,
-        1,
-        1,
-    };
-
-    final int subElemOffsets[] = {
-        0,
-        4,
-        8,
-        12,
-        20,
-        40,
-        44,
-        48,
-        64,
-        80,
-    };
-
-    protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Element", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_element s) {
-        simpleElem = Element.F32_3(RS);
-        complexElem = ScriptField_ComplexStruct.createElement(RS);
-        s.set_simpleElem(simpleElem);
-        s.set_complexElem(complexElem);
-
-        ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
-        s.bind_complexStruct(data);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_element s = new ScriptC_element(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_element_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    private void testJavaSide(RenderScript RS) {
-
-        int subElemCount = simpleElem.getSubElementCount();
-        _RS_ASSERT("subElemCount == 0", subElemCount == 0);
-        _RS_ASSERT("simpleElem.getDataKind() == USER",
-                   simpleElem.getDataKind() == DataKind.USER);
-        _RS_ASSERT("simpleElem.getDataType() == FLOAT_32",
-                   simpleElem.getDataType() == DataType.FLOAT_32);
-
-        subElemCount = complexElem.getSubElementCount();
-        _RS_ASSERT("subElemCount == 10", subElemCount == 10);
-        _RS_ASSERT("complexElem.getDataKind() == USER",
-                   complexElem.getDataKind() == DataKind.USER);
-        _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE",
-                   complexElem.getDataType() == DataType.NONE);
-        _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
-                   complexElem.getBytesSize() == ScriptField_ComplexStruct.Item.sizeof);
-
-        for (int i = 0; i < subElemCount; i ++) {
-            _RS_ASSERT("complexElem.getSubElement(i) != null",
-                       complexElem.getSubElement(i) != null);
-            _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
-                       complexElem.getSubElementName(i).equals(subElemNames[i]));
-            _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
-                       complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
-            _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
-                       complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
-        }
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testScriptSide(pRS);
-        testJavaSide(pRS);
-        passTest();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
deleted file mode 100644
index 6c95109..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_foreach extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_foreach(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_foreach s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aRaw(A);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_foreach s = new ScriptC_foreach(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_root(A);
-        s.invoke_verify_root();
-        s.forEach_foo(A, A);
-        s.invoke_verify_foo();
-        s.invoke_foreach_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
deleted file mode 100644
index 97f3a32..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_foreach_bounds.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_foreach_bounds extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_foreach_bounds(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach (bounds)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_foreach_bounds s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        final int xStart = 2;
-        final int xEnd = 5;
-        final int yStart = 3;
-        final int yEnd = 6;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aRaw(A);
-        s.set_s(s);
-        s.set_ain(A);
-        s.set_aout(A);
-        s.set_xStart(xStart);
-        s.set_xEnd(xEnd);
-        s.set_yStart(yStart);
-        s.set_yEnd(yEnd);
-        s.forEach_zero(A);
-
-        Script.LaunchOptions sc = new Script.LaunchOptions();
-        sc.setX(xStart, xEnd).setY(yStart, yEnd);
-        s.forEach_root(A, sc);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_foreach_bounds s = new ScriptC_foreach_bounds(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_verify_root();
-        s.invoke_foreach_bounds_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_fp_mad.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_fp_mad.java
deleted file mode 100644
index 5b7344d..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_fp_mad.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_fp_mad extends UnitTest {
-    private Resources mRes;
-
-    protected UT_fp_mad(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Fp_Mad", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_fp_mad s = new ScriptC_fp_mad(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_fp_mad_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_int4.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_int4.java
deleted file mode 100644
index 89a2a71..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_int4.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_int4 extends UnitTest {
-    private Resources mRes;
-
-    protected UT_int4(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "int4", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_int4 s = new ScriptC_int4(pRS, mRes, R.raw.int4);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_int4_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_kernel.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_kernel.java
deleted file mode 100644
index e0bd33e..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_kernel.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-public class UT_kernel extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-    private Allocation B;
-
-    protected UT_kernel(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Kernels (pass-by-value)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_kernel s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        s.set_dimX(X);
-        typeBuilder.setX(X);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_ain(A);
-        B = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_aout(B);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_kernel s = new ScriptC_kernel(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_init_vars(A);
-        s.forEach_root(A, B);
-        s.invoke_verify_root();
-        s.invoke_kernel_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_kernel_struct.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_kernel_struct.java
deleted file mode 100644
index 8e22810..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_kernel_struct.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-public class UT_kernel_struct extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-    private Allocation B;
-
-    protected UT_kernel_struct(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Kernels (struct pass-by-value)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_kernel_struct s) {
-        int X = 5;
-        s.set_dimX(X);
-        ScriptField_simpleStruct t;
-        t = new ScriptField_simpleStruct(RS, X);
-        s.bind_ain(t);
-        A = t.getAllocation();
-        t = new ScriptField_simpleStruct(RS, X);
-        s.bind_aout(t);
-        B = t.getAllocation();
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_kernel_struct s = new ScriptC_kernel_struct(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_init_vars(A);
-        s.forEach_root(A, B);
-        s.invoke_verify_root();
-        s.invoke_kernel_struct_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math.java
deleted file mode 100644
index 8ad462b..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_math extends UnitTest {
-    private Resources mRes;
-
-    protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math s = new ScriptC_math(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_math_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java
deleted file mode 100644
index 220509c..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_agree.java
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-import java.util.Arrays;
-import java.util.Random;
-
-public class UT_math_agree extends UnitTest {
-    private Resources mRes;
-    private Random rand;
-
-    protected UT_math_agree(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math Agreement", ctx);
-        mRes = res;
-        rand = new Random();
-    }
-
-    // packing functions
-    private Float2 pack_f2(float[] val) {
-        assert val.length == 2;
-        return new Float2(val[0], val[1]);
-    }
-    private Float3 pack_f3(float[] val) {
-        assert val.length == 3;
-        return new Float3(val[0], val[1], val[2]);
-    }
-    private Float4 pack_f4(float[] val) {
-        assert val.length == 4;
-        return new Float4(val[0], val[1], val[2], val[3]);
-    }
-    private Byte2 pack_b2(byte[] val) {
-        assert val.length == 2;
-        return new Byte2(val[0], val[1]);
-    }
-    private Byte3 pack_b3(byte[] val) {
-        assert val.length == 3;
-        return new Byte3(val[0], val[1], val[2]);
-    }
-    private Byte4 pack_b4(byte[] val) {
-        assert val.length == 4;
-        return new Byte4(val[0], val[1], val[2], val[3]);
-    }
-    private Short2 pack_s2(short[] val) {
-        assert val.length == 2;
-        return new Short2(val[0], val[1]);
-    }
-    private Short3 pack_s3(short[] val) {
-        assert val.length == 3;
-        return new Short3(val[0], val[1], val[2]);
-    }
-    private Short4 pack_s4(short[] val) {
-        assert val.length == 4;
-        return new Short4(val[0], val[1], val[2], val[3]);
-    }
-    private Int2 pack_i2(int[] val) {
-        assert val.length == 2;
-        return new Int2(val[0], val[1]);
-    }
-    private Int3 pack_i3(int[] val) {
-        assert val.length == 3;
-        return new Int3(val[0], val[1], val[2]);
-    }
-    private Int4 pack_i4(int[] val) {
-        assert val.length == 4;
-        return new Int4(val[0], val[1], val[2], val[3]);
-    }
-    private Long2 pack_l2(long[] val) {
-        assert val.length == 2;
-        return new Long2(val[0], val[1]);
-    }
-    private Long3 pack_l3(long[] val) {
-        assert val.length == 3;
-        return new Long3(val[0], val[1], val[2]);
-    }
-    private Long4 pack_l4(long[] val) {
-        assert val.length == 4;
-        return new Long4(val[0], val[1], val[2], val[3]);
-    }
-
-    // random vector generation functions
-    private float[] randvec_float(int dim) {
-        float[] fv = new float[dim];
-        for (int i = 0; i < dim; ++i)
-            fv[i] = rand.nextFloat();
-        return fv;
-    }
-    private byte[] randvec_char(int dim) {
-        byte[] cv = new byte[dim];
-        rand.nextBytes(cv);
-        return cv;
-    }
-    private short[] randvec_uchar(int dim) {
-       short[] ucv = new short[dim];
-       for (int i = 0; i < dim; ++i)
-           ucv[i] = (short)rand.nextInt(0x1 << 8);
-       return ucv;
-    }
-    private short[] randvec_short(int dim) {
-        short[] sv = new short[dim];
-        for (int i = 0; i < dim; ++i)
-            sv[i] = (short)rand.nextInt(0x1 << 16);
-        return sv;
-    }
-    private int[] randvec_ushort(int dim) {
-        int[] usv = new int[dim];
-        for (int i = 0; i < dim; ++i)
-            usv[i] = rand.nextInt(0x1 << 16);
-        return usv;
-    }
-    private int[] randvec_int(int dim) {
-        int[] iv = new int[dim];
-        for (int i = 0; i < dim; ++i)
-            iv[i] = rand.nextInt();
-        return iv;
-    }
-    private long[] randvec_uint(int dim) {
-        long[] uiv = new long[dim];
-        for (int i = 0; i < dim; ++i)
-            uiv[i] = (long)rand.nextInt() - (long)Integer.MIN_VALUE;
-        return uiv;
-    }
-    private long[] randvec_long(int dim) {
-        long[] lv = new long[dim];
-        for (int i = 0; i < dim; ++i)
-            lv[i] = rand.nextLong();
-        return lv;
-    }
-    // TODO:  unsigned long generator
-
-    // min reference functions
-    private float min(float v1, float v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private float[] min(float[] v1, float[] v2) {
-        assert v1.length == v2.length;
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private byte min(byte v1, byte v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private byte[] min(byte[] v1, byte[] v2) {
-        assert v1.length == v2.length;
-        byte[] rv = new byte[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private short min(short v1, short v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private short[] min(short[] v1, short[] v2) {
-        assert v1.length == v2.length;
-        short[] rv = new short[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private int min(int v1, int v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private int[] min(int[] v1, int[] v2) {
-        assert v1.length == v2.length;
-        int[] rv = new int[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    private long min(long v1, long v2) {
-        return v1 < v2 ? v1 : v2;
-    }
-    private long[] min(long[] v1, long[] v2) {
-        assert v1.length == v2.length;
-        long[] rv = new long[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2[i]);
-        return rv;
-    }
-    // TODO:  unsigned long version of min
-
-    // max reference functions
-    private float max(float v1, float v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private float[] max(float[] v1, float[] v2) {
-        assert v1.length == v2.length;
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private byte max(byte v1, byte v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private byte[] max(byte[] v1, byte[] v2) {
-        assert v1.length == v2.length;
-        byte[] rv = new byte[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private short max(short v1, short v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private short[] max(short[] v1, short[] v2) {
-        assert v1.length == v2.length;
-        short[] rv = new short[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private int max(int v1, int v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private int[] max(int[] v1, int[] v2) {
-        assert v1.length == v2.length;
-        int[] rv = new int[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    private long max(long v1, long v2) {
-        return v1 > v2 ? v1 : v2;
-    }
-    private long[] max(long[] v1, long[] v2) {
-        assert v1.length == v2.length;
-        long[] rv = new long[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2[i]);
-        return rv;
-    }
-    // TODO:  unsigned long version of max
-
-    // fmin reference functions
-    private float fmin(float v1, float v2) {
-        return min(v1, v2);
-    }
-    private float[] fmin(float[] v1, float[] v2) {
-        return min(v1, v2);
-    }
-    private float[] fmin(float[] v1, float v2) {
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = min(v1[i], v2);
-        return rv;
-    }
-
-    // fmax reference functions
-    private float fmax(float v1, float v2) {
-        return max(v1, v2);
-    }
-    private float[] fmax(float[] v1, float[] v2) {
-        return max(v1, v2);
-    }
-    private float[] fmax(float[] v1, float v2) {
-        float[] rv = new float[v1.length];
-        for (int i = 0; i < v1.length; ++i)
-            rv[i] = max(v1[i], v2);
-        return rv;
-    }
-
-    private void initializeValues(ScriptC_math_agree s) {
-        float x = rand.nextFloat();
-        float y = rand.nextFloat();
-
-        s.set_x(x);
-        s.set_y(y);
-        s.set_result_add(x + y);
-        s.set_result_sub(x - y);
-        s.set_result_mul(x * y);
-        s.set_result_div(x / y);
-
-        // Generate random vectors of all types
-        float rand_f1_0 = rand.nextFloat();
-        float[] rand_f2_0 = randvec_float(2);
-        float[] rand_f3_0 = randvec_float(3);
-        float[] rand_f4_0 = randvec_float(4);
-        float rand_f1_1 = rand.nextFloat();
-        float[] rand_f2_1 = randvec_float(2);
-        float[] rand_f3_1 = randvec_float(3);
-        float[] rand_f4_1 = randvec_float(4);
-        short rand_uc1_0 = (short)rand.nextInt(0x1 << 8);
-        short[] rand_uc2_0 = randvec_uchar(2);
-        short[] rand_uc3_0 = randvec_uchar(3);
-        short[] rand_uc4_0 = randvec_uchar(4);
-        short rand_uc1_1 = (short)rand.nextInt(0x1 << 8);
-        short[] rand_uc2_1 = randvec_uchar(2);
-        short[] rand_uc3_1 = randvec_uchar(3);
-        short[] rand_uc4_1 = randvec_uchar(4);
-        short rand_ss1_0 = (short)rand.nextInt(0x1 << 16);
-        short[] rand_ss2_0 = randvec_short(2);
-        short[] rand_ss3_0 = randvec_short(3);
-        short[] rand_ss4_0 = randvec_short(4);
-        short rand_ss1_1 = (short)rand.nextInt(0x1 << 16);
-        short[] rand_ss2_1 = randvec_short(2);
-        short[] rand_ss3_1 = randvec_short(3);
-        short[] rand_ss4_1 = randvec_short(4);
-        int rand_us1_0 = rand.nextInt(0x1 << 16);
-        int[] rand_us2_0 = randvec_ushort(2);
-        int[] rand_us3_0 = randvec_ushort(3);
-        int[] rand_us4_0 = randvec_ushort(4);
-        int rand_us1_1 = rand.nextInt(0x1 << 16);
-        int[] rand_us2_1 = randvec_ushort(2);
-        int[] rand_us3_1 = randvec_ushort(3);
-        int[] rand_us4_1 = randvec_ushort(4);
-        int rand_si1_0 = rand.nextInt();
-        int[] rand_si2_0 = randvec_int(2);
-        int[] rand_si3_0 = randvec_int(3);
-        int[] rand_si4_0 = randvec_int(4);
-        int rand_si1_1 = rand.nextInt();
-        int[] rand_si2_1 = randvec_int(2);
-        int[] rand_si3_1 = randvec_int(3);
-        int[] rand_si4_1 = randvec_int(4);
-        long rand_ui1_0 = (long)rand.nextInt() - (long)Integer.MIN_VALUE;
-        long[] rand_ui2_0 = randvec_uint(2);
-        long[] rand_ui3_0 = randvec_uint(3);
-        long[] rand_ui4_0 = randvec_uint(4);
-        long rand_ui1_1 = (long)rand.nextInt() - (long)Integer.MIN_VALUE;
-        long[] rand_ui2_1 = randvec_uint(2);
-        long[] rand_ui3_1 = randvec_uint(3);
-        long[] rand_ui4_1 = randvec_uint(4);
-        long rand_sl1_0 = rand.nextLong();
-        long[] rand_sl2_0 = randvec_long(2);
-        long[] rand_sl3_0 = randvec_long(3);
-        long[] rand_sl4_0 = randvec_long(4);
-        long rand_sl1_1 = rand.nextLong();
-        long[] rand_sl2_1 = randvec_long(2);
-        long[] rand_sl3_1 = randvec_long(3);
-        long[] rand_sl4_1 = randvec_long(4);
-        byte rand_sc1_0 = (byte)rand.nextInt(0x1 << 8);
-        byte[] rand_sc2_0 = randvec_char(2);
-        byte[] rand_sc3_0 = randvec_char(3);
-        byte[] rand_sc4_0 = randvec_char(4);
-        byte rand_sc1_1 = (byte)rand.nextInt(0x1 << 8);
-        byte[] rand_sc2_1 = randvec_char(2);
-        byte[] rand_sc3_1 = randvec_char(3);
-        byte[] rand_sc4_1 = randvec_char(4);
-        // TODO:  generate unsigned long vectors
-
-        // Set random vectors in renderscript code
-        s.set_rand_f1_0(rand_f1_0);
-        s.set_rand_f2_0(pack_f2(rand_f2_0));
-        s.set_rand_f3_0(pack_f3(rand_f3_0));
-        s.set_rand_f4_0(pack_f4(rand_f4_0));
-        s.set_rand_f1_1(rand_f1_1);
-        s.set_rand_f2_1(pack_f2(rand_f2_1));
-        s.set_rand_f3_1(pack_f3(rand_f3_1));
-        s.set_rand_f4_1(pack_f4(rand_f4_1));
-        s.set_rand_uc1_1(rand_uc1_1);
-        s.set_rand_uc2_1(pack_s2(rand_uc2_1));
-        s.set_rand_uc3_1(pack_s3(rand_uc3_1));
-        s.set_rand_uc4_1(pack_s4(rand_uc4_1));
-        s.set_rand_ss1_0(rand_ss1_0);
-        s.set_rand_ss2_0(pack_s2(rand_ss2_0));
-        s.set_rand_ss3_0(pack_s3(rand_ss3_0));
-        s.set_rand_ss4_0(pack_s4(rand_ss4_0));
-        s.set_rand_ss1_1(rand_ss1_1);
-        s.set_rand_ss2_1(pack_s2(rand_ss2_1));
-        s.set_rand_ss3_1(pack_s3(rand_ss3_1));
-        s.set_rand_ss4_1(pack_s4(rand_ss4_1));
-        s.set_rand_us1_0(rand_us1_0);
-        s.set_rand_us2_0(pack_i2(rand_us2_0));
-        s.set_rand_us3_0(pack_i3(rand_us3_0));
-        s.set_rand_us4_0(pack_i4(rand_us4_0));
-        s.set_rand_us1_1(rand_us1_1);
-        s.set_rand_us2_1(pack_i2(rand_us2_1));
-        s.set_rand_us3_1(pack_i3(rand_us3_1));
-        s.set_rand_us4_1(pack_i4(rand_us4_1));
-        s.set_rand_si1_0(rand_si1_0);
-        s.set_rand_si2_0(pack_i2(rand_si2_0));
-        s.set_rand_si3_0(pack_i3(rand_si3_0));
-        s.set_rand_si4_0(pack_i4(rand_si4_0));
-        s.set_rand_si1_1(rand_si1_1);
-        s.set_rand_si2_1(pack_i2(rand_si2_1));
-        s.set_rand_si3_1(pack_i3(rand_si3_1));
-        s.set_rand_si4_1(pack_i4(rand_si4_1));
-        s.set_rand_ui1_0(rand_ui1_0);
-        s.set_rand_ui2_0(pack_l2(rand_ui2_0));
-        s.set_rand_ui3_0(pack_l3(rand_ui3_0));
-        s.set_rand_ui4_0(pack_l4(rand_ui4_0));
-        s.set_rand_ui1_1(rand_ui1_1);
-        s.set_rand_ui2_1(pack_l2(rand_ui2_1));
-        s.set_rand_ui3_1(pack_l3(rand_ui3_1));
-        s.set_rand_ui4_1(pack_l4(rand_ui4_1));
-        s.set_rand_sl1_0(rand_sl1_0);
-        s.set_rand_sl2_0(pack_l2(rand_sl2_0));
-        s.set_rand_sl3_0(pack_l3(rand_sl3_0));
-        s.set_rand_sl4_0(pack_l4(rand_sl4_0));
-        s.set_rand_sl1_1(rand_sl1_1);
-        s.set_rand_sl2_1(pack_l2(rand_sl2_1));
-        s.set_rand_sl3_1(pack_l3(rand_sl3_1));
-        s.set_rand_sl4_1(pack_l4(rand_sl4_1));
-        s.set_rand_uc1_0(rand_uc1_0);
-        s.set_rand_uc2_0(pack_s2(rand_uc2_0));
-        s.set_rand_uc3_0(pack_s3(rand_uc3_0));
-        s.set_rand_uc4_0(pack_s4(rand_uc4_0));
-        s.set_rand_sc1_0(rand_sc1_0);
-        s.set_rand_sc2_0(pack_b2(rand_sc2_0));
-        s.set_rand_sc3_0(pack_b3(rand_sc3_0));
-        s.set_rand_sc4_0(pack_b4(rand_sc4_0));
-        s.set_rand_sc1_1(rand_sc1_1);
-        s.set_rand_sc2_1(pack_b2(rand_sc2_1));
-        s.set_rand_sc3_1(pack_b3(rand_sc3_1));
-        s.set_rand_sc4_1(pack_b4(rand_sc4_1));
-        // TODO:  set unsigned long vectors
-
-        // Set results for min
-        s.set_min_rand_f1_f1(min(rand_f1_0, rand_f1_1));
-        s.set_min_rand_f2_f2(pack_f2(min(rand_f2_0, rand_f2_1)));
-        s.set_min_rand_f3_f3(pack_f3(min(rand_f3_0, rand_f3_1)));
-        s.set_min_rand_f4_f4(pack_f4(min(rand_f4_0, rand_f4_1)));
-        s.set_min_rand_uc1_uc1(min(rand_uc1_0, rand_uc1_1));
-        s.set_min_rand_uc2_uc2(pack_s2(min(rand_uc2_0, rand_uc2_1)));
-        s.set_min_rand_uc3_uc3(pack_s3(min(rand_uc3_0, rand_uc3_1)));
-        s.set_min_rand_uc4_uc4(pack_s4(min(rand_uc4_0, rand_uc4_1)));
-        s.set_min_rand_ss1_ss1(min(rand_ss1_0, rand_ss1_1));
-        s.set_min_rand_ss2_ss2(pack_s2(min(rand_ss2_0, rand_ss2_1)));
-        s.set_min_rand_ss3_ss3(pack_s3(min(rand_ss3_0, rand_ss3_1)));
-        s.set_min_rand_ss4_ss4(pack_s4(min(rand_ss4_0, rand_ss4_1)));
-        s.set_min_rand_us1_us1(min(rand_us1_0, rand_us1_1));
-        s.set_min_rand_us2_us2(pack_i2(min(rand_us2_0, rand_us2_1)));
-        s.set_min_rand_us3_us3(pack_i3(min(rand_us3_0, rand_us3_1)));
-        s.set_min_rand_us4_us4(pack_i4(min(rand_us4_0, rand_us4_1)));
-        s.set_min_rand_si1_si1(min(rand_si1_0, rand_si1_1));
-        s.set_min_rand_si2_si2(pack_i2(min(rand_si2_0, rand_si2_1)));
-        s.set_min_rand_si3_si3(pack_i3(min(rand_si3_0, rand_si3_1)));
-        s.set_min_rand_si4_si4(pack_i4(min(rand_si4_0, rand_si4_1)));
-        s.set_min_rand_ui1_ui1(min(rand_ui1_0, rand_ui1_1));
-        s.set_min_rand_ui2_ui2(pack_l2(min(rand_ui2_0, rand_ui2_1)));
-        s.set_min_rand_ui3_ui3(pack_l3(min(rand_ui3_0, rand_ui3_1)));
-        s.set_min_rand_ui4_ui4(pack_l4(min(rand_ui4_0, rand_ui4_1)));
-        s.set_min_rand_sl1_sl1(min(rand_sl1_0, rand_sl1_1));
-        s.set_min_rand_sl2_sl2(pack_l2(min(rand_sl2_0, rand_sl2_1)));
-        s.set_min_rand_sl3_sl3(pack_l3(min(rand_sl3_0, rand_sl3_1)));
-        s.set_min_rand_sl4_sl4(pack_l4(min(rand_sl4_0, rand_sl4_1)));
-        s.set_min_rand_sc1_sc1(min(rand_sc1_0, rand_sc1_1));
-        s.set_min_rand_sc2_sc2(pack_b2(min(rand_sc2_0, rand_sc2_1)));
-        s.set_min_rand_sc3_sc3(pack_b3(min(rand_sc3_0, rand_sc3_1)));
-        s.set_min_rand_sc4_sc4(pack_b4(min(rand_sc4_0, rand_sc4_1)));
-        // TODO:  set results for unsigned long min
-
-        // Set results for max
-        s.set_max_rand_f1_f1(max(rand_f1_0, rand_f1_1));
-        s.set_max_rand_f2_f2(pack_f2(max(rand_f2_0, rand_f2_1)));
-        s.set_max_rand_f3_f3(pack_f3(max(rand_f3_0, rand_f3_1)));
-        s.set_max_rand_f4_f4(pack_f4(max(rand_f4_0, rand_f4_1)));
-        s.set_max_rand_uc1_uc1(max(rand_uc1_0, rand_uc1_1));
-        s.set_max_rand_uc2_uc2(pack_s2(max(rand_uc2_0, rand_uc2_1)));
-        s.set_max_rand_uc3_uc3(pack_s3(max(rand_uc3_0, rand_uc3_1)));
-        s.set_max_rand_uc4_uc4(pack_s4(max(rand_uc4_0, rand_uc4_1)));
-        s.set_max_rand_ss1_ss1(max(rand_ss1_0, rand_ss1_1));
-        s.set_max_rand_ss2_ss2(pack_s2(max(rand_ss2_0, rand_ss2_1)));
-        s.set_max_rand_ss3_ss3(pack_s3(max(rand_ss3_0, rand_ss3_1)));
-        s.set_max_rand_ss4_ss4(pack_s4(max(rand_ss4_0, rand_ss4_1)));
-        s.set_max_rand_us1_us1(max(rand_us1_0, rand_us1_1));
-        s.set_max_rand_us2_us2(pack_i2(max(rand_us2_0, rand_us2_1)));
-        s.set_max_rand_us3_us3(pack_i3(max(rand_us3_0, rand_us3_1)));
-        s.set_max_rand_us4_us4(pack_i4(max(rand_us4_0, rand_us4_1)));
-        s.set_max_rand_si1_si1(max(rand_si1_0, rand_si1_1));
-        s.set_max_rand_si2_si2(pack_i2(max(rand_si2_0, rand_si2_1)));
-        s.set_max_rand_si3_si3(pack_i3(max(rand_si3_0, rand_si3_1)));
-        s.set_max_rand_si4_si4(pack_i4(max(rand_si4_0, rand_si4_1)));
-        s.set_max_rand_ui1_ui1(max(rand_ui1_0, rand_ui1_1));
-        s.set_max_rand_ui2_ui2(pack_l2(max(rand_ui2_0, rand_ui2_1)));
-        s.set_max_rand_ui3_ui3(pack_l3(max(rand_ui3_0, rand_ui3_1)));
-        s.set_max_rand_ui4_ui4(pack_l4(max(rand_ui4_0, rand_ui4_1)));
-        s.set_max_rand_sl1_sl1(max(rand_sl1_0, rand_sl1_1));
-        s.set_max_rand_sl2_sl2(pack_l2(max(rand_sl2_0, rand_sl2_1)));
-        s.set_max_rand_sl3_sl3(pack_l3(max(rand_sl3_0, rand_sl3_1)));
-        s.set_max_rand_sl4_sl4(pack_l4(max(rand_sl4_0, rand_sl4_1)));
-        s.set_max_rand_sc1_sc1(max(rand_sc1_0, rand_sc1_1));
-        s.set_max_rand_sc2_sc2(pack_b2(max(rand_sc2_0, rand_sc2_1)));
-        s.set_max_rand_sc3_sc3(pack_b3(max(rand_sc3_0, rand_sc3_1)));
-        s.set_max_rand_sc4_sc4(pack_b4(max(rand_sc4_0, rand_sc4_1)));
-
-        // TODO:  set results for unsigned long max
-
-        // Set results for fmin
-        s.set_fmin_rand_f1_f1(fmin(rand_f1_0, rand_f1_1));
-        s.set_fmin_rand_f2_f2(pack_f2(fmin(rand_f2_0, rand_f2_1)));
-        s.set_fmin_rand_f3_f3(pack_f3(fmin(rand_f3_0, rand_f3_1)));
-        s.set_fmin_rand_f4_f4(pack_f4(fmin(rand_f4_0, rand_f4_1)));
-        s.set_fmin_rand_f2_f1(pack_f2(fmin(rand_f2_0, rand_f1_1)));
-        s.set_fmin_rand_f3_f1(pack_f3(fmin(rand_f3_0, rand_f1_1)));
-        s.set_fmin_rand_f4_f1(pack_f4(fmin(rand_f4_0, rand_f1_1)));
-
-        // Set results for fmax
-        s.set_fmax_rand_f1_f1(fmax(rand_f1_0, rand_f1_1));
-        s.set_fmax_rand_f2_f2(pack_f2(fmax(rand_f2_0, rand_f2_1)));
-        s.set_fmax_rand_f3_f3(pack_f3(fmax(rand_f3_0, rand_f3_1)));
-        s.set_fmax_rand_f4_f4(pack_f4(fmax(rand_f4_0, rand_f4_1)));
-        s.set_fmax_rand_f2_f1(pack_f2(fmax(rand_f2_0, rand_f1_1)));
-        s.set_fmax_rand_f3_f1(pack_f3(fmax(rand_f3_0, rand_f1_1)));
-        s.set_fmax_rand_f4_f1(pack_f4(fmax(rand_f4_0, rand_f1_1)));
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math_agree s = new ScriptC_math_agree(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeValues(s);
-        s.invoke_math_agree_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_conformance.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_conformance.java
deleted file mode 100644
index 620eeb5..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_math_conformance.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_math_conformance extends UnitTest {
-    private Resources mRes;
-
-    protected UT_math_conformance(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math Conformance", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math_conformance s =
-                new ScriptC_math_conformance(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_math_conformance_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-        passTest();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
deleted file mode 100644
index 29e5025..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Mesh.*;
-
-public class UT_mesh extends UnitTest {
-    private Resources mRes;
-
-    Mesh mesh;
-
-    protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Mesh", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_mesh s) {
-        Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10);
-        Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10);
-
-        Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10);
-        Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10);
-
-        Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS);
-        mBuilder.addVertexAllocation(vAlloc0);
-        mBuilder.addVertexAllocation(vAlloc1);
-
-        mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT);
-        mBuilder.addIndexSetType(Primitive.LINE);
-        mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE);
-
-        s.set_mesh(mBuilder.create());
-        s.set_vertexAlloc0(vAlloc0);
-        s.set_vertexAlloc1(vAlloc1);
-        s.set_indexAlloc0(iAlloc0);
-        s.set_indexAlloc2(iAlloc2);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_mesh s = new ScriptC_mesh(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_mesh_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    private void testJavaSide(RenderScript RS) {
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testScriptSide(pRS);
-        testJavaSide(pRS);
-        passTest();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_min.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_min.java
deleted file mode 100644
index 137cae9..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_min.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_min extends UnitTest {
-    private Resources mRes;
-
-    protected UT_min(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Min (relaxed)", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_min s = new ScriptC_min(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_min_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
deleted file mode 100644
index 69526a8..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_noroot.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_noroot extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_noroot(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach (no root)", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_noroot s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aRaw(A);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_noroot s = new ScriptC_noroot(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_foo(A, A);
-        s.invoke_verify_foo();
-        s.invoke_noroot_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
deleted file mode 100644
index c1234f0..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_primitives extends UnitTest {
-    private Resources mRes;
-
-    protected UT_primitives(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Primitives", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_primitives s) {
-        float pF = s.get_floatTest();
-        if (pF != 1.99f) {
-            return false;
-        }
-        s.set_floatTest(2.99f);
-
-        double pD = s.get_doubleTest();
-        if (pD != 2.05) {
-            return false;
-        }
-        s.set_doubleTest(3.05);
-
-        byte pC = s.get_charTest();
-        if (pC != -8) {
-            return false;
-        }
-        s.set_charTest((byte)-16);
-
-        short pS = s.get_shortTest();
-        if (pS != -16) {
-            return false;
-        }
-        s.set_shortTest((short)-32);
-
-        int pI = s.get_intTest();
-        if (pI != -32) {
-            return false;
-        }
-        s.set_intTest(-64);
-
-        long pL = s.get_longTest();
-        if (pL != 17179869184l) {
-            return false;
-        }
-        s.set_longTest(17179869185l);
-
-        long puL = s.get_ulongTest();
-        if (puL != 4611686018427387904L) {
-            return false;
-        }
-        s.set_ulongTest(4611686018427387903L);
-
-
-        long pLL = s.get_longlongTest();
-        if (pLL != 68719476736L) {
-            return false;
-        }
-        s.set_longlongTest(68719476735L);
-
-        long pu64 = s.get_uint64_tTest();
-        if (pu64 != 117179869184l) {
-            return false;
-        }
-        s.set_uint64_tTest(117179869185l);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_primitives s = new ScriptC_primitives(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            failTest();
-        } else {
-            s.invoke_primitives_test(0, 0);
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
deleted file mode 100644
index 046a215..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.ProgramRaster;
-import android.renderscript.ProgramRaster.CullMode;
-
-public class UT_program_raster extends UnitTest {
-    private Resources mRes;
-
-    ProgramRaster pointSpriteEnabled;
-    ProgramRaster cullMode;
-
-    protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ProgramRaster", ctx);
-        mRes = res;
-    }
-
-    private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
-        ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
-        b.setCullMode(CullMode.BACK);
-        b.setPointSpriteEnabled(false);
-        return b;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
-        ProgramRaster.Builder b = getDefaultBuilder(RS);
-        pointSpriteEnabled = b.setPointSpriteEnabled(true).create();
-        b = getDefaultBuilder(RS);
-        cullMode = b.setCullMode(CullMode.FRONT).create();
-
-        s.set_pointSpriteEnabled(pointSpriteEnabled);
-        s.set_cullMode(cullMode);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_program_raster s = new ScriptC_program_raster(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_program_raster_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    private void testJavaSide(RenderScript RS) {
-        _RS_ASSERT("pointSpriteEnabled.isPointSpriteEnabled() == true",
-                    pointSpriteEnabled.isPointSpriteEnabled() == true);
-        _RS_ASSERT("pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK",
-                    pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK);
-
-        _RS_ASSERT("cullMode.isPointSpriteEnabled() == false",
-                    cullMode.isPointSpriteEnabled() == false);
-        _RS_ASSERT("cullMode.getCullMode() == ProgramRaster.CullMode.FRONT",
-                    cullMode.getCullMode() == ProgramRaster.CullMode.FRONT);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testScriptSide(pRS);
-        testJavaSide(pRS);
-        passTest();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
deleted file mode 100644
index 6510b6b..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.ProgramStore.BlendDstFunc;
-import android.renderscript.ProgramStore.BlendSrcFunc;
-import android.renderscript.ProgramStore.Builder;
-import android.renderscript.ProgramStore.DepthFunc;
-
-public class UT_program_store extends UnitTest {
-    private Resources mRes;
-
-    ProgramStore ditherEnable;
-    ProgramStore colorRWriteEnable;
-    ProgramStore colorGWriteEnable;
-    ProgramStore colorBWriteEnable;
-    ProgramStore colorAWriteEnable;
-    ProgramStore blendSrc;
-    ProgramStore blendDst;
-    ProgramStore depthWriteEnable;
-    ProgramStore depthFunc;
-
-    protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ProgramStore", ctx);
-        mRes = res;
-    }
-
-    private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
-        ProgramStore.Builder b = new ProgramStore.Builder(RS);
-        b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
-        b.setColorMaskEnabled(false, false, false, false);
-        b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
-        b.setDepthMaskEnabled(false);
-        b.setDitherEnabled(false);
-        return b;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
-        ProgramStore.Builder b = getDefaultBuilder(RS);
-        ditherEnable = b.setDitherEnabled(true).create();
-
-        b = getDefaultBuilder(RS);
-        colorRWriteEnable = b.setColorMaskEnabled(true,  false, false, false).create();
-
-        b = getDefaultBuilder(RS);
-        colorGWriteEnable = b.setColorMaskEnabled(false, true,  false, false).create();
-
-        b = getDefaultBuilder(RS);
-        colorBWriteEnable = b.setColorMaskEnabled(false, false, true,  false).create();
-
-        b = getDefaultBuilder(RS);
-        colorAWriteEnable = b.setColorMaskEnabled(false, false, false, true).create();
-
-        b = getDefaultBuilder(RS);
-        blendSrc = b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
-                                  ProgramStore.BlendDstFunc.ZERO).create();
-
-        b = getDefaultBuilder(RS);
-        blendDst = b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
-                                  ProgramStore.BlendDstFunc.DST_ALPHA).create();
-
-        b = getDefaultBuilder(RS);
-        depthWriteEnable = b.setDepthMaskEnabled(true).create();
-
-        b = getDefaultBuilder(RS);
-        depthFunc = b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create();
-
-        s.set_ditherEnable(ditherEnable);
-        s.set_colorRWriteEnable(colorRWriteEnable);
-        s.set_colorGWriteEnable(colorGWriteEnable);
-        s.set_colorBWriteEnable(colorBWriteEnable);
-        s.set_colorAWriteEnable(colorAWriteEnable);
-        s.set_blendSrc(blendSrc);
-        s.set_blendDst(blendDst);
-        s.set_depthWriteEnable(depthWriteEnable);
-        s.set_depthFunc(depthFunc);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_program_store s = new ScriptC_program_store(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_program_store_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    void checkObject(ProgramStore ps,
-                     boolean depthMask,
-                     DepthFunc df,
-                     BlendSrcFunc bsf,
-                     BlendDstFunc bdf,
-                     boolean R,
-                     boolean G,
-                     boolean B,
-                     boolean A,
-                     boolean dither) {
-        _RS_ASSERT("ps.isDepthMaskEnabled() == depthMask", ps.isDepthMaskEnabled() == depthMask);
-        _RS_ASSERT("ps.getDepthFunc() == df", ps.getDepthFunc() == df);
-        _RS_ASSERT("ps.getBlendSrcFunc() == bsf", ps.getBlendSrcFunc() == bsf);
-        _RS_ASSERT("ps.getBlendDstFunc() == bdf", ps.getBlendDstFunc() == bdf);
-        _RS_ASSERT("ps.isColorMaskRedEnabled() == R", ps.isColorMaskRedEnabled() == R);
-        _RS_ASSERT("ps.isColorMaskGreenEnabled() == G", ps.isColorMaskGreenEnabled() == G);
-        _RS_ASSERT("ps.isColorMaskBlueEnabled () == B", ps.isColorMaskBlueEnabled () == B);
-        _RS_ASSERT("ps.isColorMaskAlphaEnabled() == A", ps.isColorMaskAlphaEnabled() == A);
-        _RS_ASSERT("ps.isDitherEnabled() == dither", ps.isDitherEnabled() == dither);
-    }
-
-    void varyBuilderColorAndDither(ProgramStore.Builder pb,
-                                   boolean depthMask,
-                                   DepthFunc df,
-                                   BlendSrcFunc bsf,
-                                   BlendDstFunc bdf) {
-        for (int r = 0; r <= 1; r++) {
-            boolean isR = (r == 1);
-            for (int g = 0; g <= 1; g++) {
-                boolean isG = (g == 1);
-                for (int b = 0; b <= 1; b++) {
-                    boolean isB = (b == 1);
-                    for (int a = 0; a <= 1; a++) {
-                        boolean isA = (a == 1);
-                        for (int dither = 0; dither <= 1; dither++) {
-                            boolean isDither = (dither == 1);
-                            pb.setDitherEnabled(isDither);
-                            pb.setColorMaskEnabled(isR, isG, isB, isA);
-                            ProgramStore ps = pb.create();
-                            checkObject(ps, depthMask, df, bsf, bdf, isR, isG, isB, isA, isDither);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public void testJavaSide(RenderScript RS) {
-        for (int depth = 0; depth <= 1; depth++) {
-            boolean depthMask = (depth == 1);
-            for (DepthFunc df : DepthFunc.values()) {
-                for (BlendSrcFunc bsf : BlendSrcFunc.values()) {
-                    for (BlendDstFunc bdf : BlendDstFunc.values()) {
-                        ProgramStore.Builder b = new ProgramStore.Builder(RS);
-                        b.setDepthFunc(df);
-                        b.setDepthMaskEnabled(depthMask);
-                        b.setBlendFunc(bsf, bdf);
-                        varyBuilderColorAndDither(b, depthMask, df, bsf, bdf);
-                    }
-                }
-            }
-        }
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testJavaSide(pRS);
-        testScriptSide(pRS);
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_refcount.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_refcount.java
deleted file mode 100644
index 22bbd2f..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_refcount.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_refcount extends UnitTest {
-    private Resources mRes;
-
-    protected UT_refcount(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Refcount", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_refcount s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 500;
-        int Y = 700;
-        typeBuilder.setX(X).setY(Y);
-        Allocation A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_globalA(A);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        pRS.setMessageHandler(mRsMessage);
-        ScriptC_refcount s = new ScriptC_refcount(pRS);
-        initializeGlobals(pRS, s);
-        s.invoke_refcount_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rsdebug.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rsdebug.java
deleted file mode 100644
index 548288b..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rsdebug.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rsdebug extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rsdebug(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsDebug", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rsdebug s = new ScriptC_rsdebug(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rsdebug(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java
deleted file mode 100644
index f000412..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rstime extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTime", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstime s = new ScriptC_rstime(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.setTimeZone("America/Los_Angeles");
-        s.invoke_test_rstime(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstypes.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstypes.java
deleted file mode 100644
index f677f10..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstypes.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rstypes extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstypes(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTypes", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstypes s = new ScriptC_rstypes(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rstypes(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
deleted file mode 100644
index 00c850c..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.renderscript.Sampler;
-import android.renderscript.Sampler.Value;
-
-public class UT_sampler extends UnitTest {
-    private Resources mRes;
-
-    Sampler minification;
-    Sampler magnification;
-    Sampler wrapS;
-    Sampler wrapT;
-    Sampler anisotropy;
-
-    protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Sampler", ctx);
-        mRes = res;
-    }
-
-    private Sampler.Builder getDefaultBuilder(RenderScript RS) {
-        Sampler.Builder b = new Sampler.Builder(RS);
-        b.setMinification(Value.NEAREST);
-        b.setMagnification(Value.NEAREST);
-        b.setWrapS(Value.CLAMP);
-        b.setWrapT(Value.CLAMP);
-        b.setAnisotropy(1.0f);
-        return b;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
-        Sampler.Builder b = getDefaultBuilder(RS);
-        b.setMinification(Value.LINEAR_MIP_LINEAR);
-        minification = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setMagnification(Value.LINEAR);
-        magnification = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setWrapS(Value.WRAP);
-        wrapS = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setWrapT(Value.WRAP);
-        wrapT = b.create();
-
-        b = getDefaultBuilder(RS);
-        b.setAnisotropy(8.0f);
-        anisotropy = b.create();
-
-        s.set_minification(minification);
-        s.set_magnification(magnification);
-        s.set_wrapS(wrapS);
-        s.set_wrapT(wrapT);
-        s.set_anisotropy(anisotropy);
-    }
-
-    private void testScriptSide(RenderScript pRS) {
-        ScriptC_sampler s = new ScriptC_sampler(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_sampler_test();
-        pRS.finish();
-        waitForMessage();
-    }
-
-    private void testJavaSide(RenderScript RS) {
-        _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST",
-                    minification.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR",
-                    minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR);
-        _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP",
-                    minification.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP",
-                    minification.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("minification.getAnisotropy() == 1.0f",
-                    minification.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR",
-                    magnification.getMagnification() == Sampler.Value.LINEAR);
-        _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST",
-                    magnification.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP",
-                    magnification.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP",
-                    magnification.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("magnification.getAnisotropy() == 1.0f",
-                    magnification.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST",
-                    wrapS.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST",
-                    wrapS.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP",
-                    wrapS.getWrapS() == Sampler.Value.WRAP);
-        _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP",
-                    wrapS.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("wrapS.getAnisotropy() == 1.0f",
-                    wrapS.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST",
-                    wrapT.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST",
-                    wrapT.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP",
-                    wrapT.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP",
-                    wrapT.getWrapT() == Sampler.Value.WRAP);
-        _RS_ASSERT("wrapT.getAnisotropy() == 1.0f",
-                    wrapT.getAnisotropy() == 1.0f);
-
-        _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST",
-                    anisotropy.getMagnification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST",
-                    anisotropy.getMinification() == Sampler.Value.NEAREST);
-        _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP",
-                    anisotropy.getWrapS() == Sampler.Value.CLAMP);
-        _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP",
-                    anisotropy.getWrapT() == Sampler.Value.CLAMP);
-        _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f",
-                    anisotropy.getAnisotropy() == 8.0f);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        testScriptSide(pRS);
-        testJavaSide(pRS);
-        passTest();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
deleted file mode 100644
index 6f47b72..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_struct extends UnitTest {
-    private Resources mRes;
-
-    protected UT_struct(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Struct", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_struct s = new ScriptC_struct(pRS);
-        pRS.setMessageHandler(mRsMessage);
-
-        ScriptField_Point2 p = new ScriptField_Point2(pRS, 1);
-        ScriptField_Point2.Item i = new ScriptField_Point2.Item();
-        int val = 100;
-        i.x = val;
-        i.y = val;
-        p.set(i, 0, true);
-        s.bind_point2(p);
-        s.invoke_struct_test(val);
-        pRS.finish();
-        waitForMessage();
-
-        val = 200;
-        p.set_x(0, val, true);
-        p.set_y(0, val, true);
-        s.invoke_struct_test(val);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_unsigned.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_unsigned.java
deleted file mode 100644
index 9ea0f8a..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_unsigned.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_unsigned extends UnitTest {
-    private Resources mRes;
-
-    protected UT_unsigned(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Unsigned", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_unsigned s) {
-        short pUC = s.get_uc();
-        if (pUC != 5) {
-            return false;
-        }
-        s.set_uc((short)129);
-
-        long pUI = s.get_ui();
-        if (pUI != 37) {
-            return false;
-        }
-        s.set_ui(0x7fffffff);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_unsigned s = new ScriptC_unsigned(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            failTest();
-        } else {
-            s.invoke_unsigned_test();
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
deleted file mode 100644
index 91cc0af..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_vector extends UnitTest {
-    private Resources mRes;
-
-    protected UT_vector(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Vector", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_vector s) {
-        Float2 F2 = s.get_f2();
-        if (F2.x != 1.0f || F2.y != 2.0f) {
-            return false;
-        }
-        F2.x = 2.99f;
-        F2.y = 3.99f;
-        s.set_f2(F2);
-
-        Float3 F3 = s.get_f3();
-        if (F3.x != 1.0f || F3.y != 2.0f || F3.z != 3.0f) {
-            return false;
-        }
-        F3.x = 2.99f;
-        F3.y = 3.99f;
-        F3.z = 4.99f;
-        s.set_f3(F3);
-
-        Float4 F4 = s.get_f4();
-        if (F4.x != 1.0f || F4.y != 2.0f || F4.z != 3.0f || F4.w != 4.0f) {
-            return false;
-        }
-        F4.x = 2.99f;
-        F4.y = 3.99f;
-        F4.z = 4.99f;
-        F4.w = 5.99f;
-        s.set_f4(F4);
-
-        Double2 D2 = s.get_d2();
-        if (D2.x != 1.0 || D2.y != 2.0) {
-            return false;
-        }
-        D2.x = 2.99;
-        D2.y = 3.99;
-        s.set_d2(D2);
-
-        Double3 D3 = s.get_d3();
-        if (D3.x != 1.0 || D3.y != 2.0 || D3.z != 3.0) {
-            return false;
-        }
-        D3.x = 2.99;
-        D3.y = 3.99;
-        D3.z = 4.99;
-        s.set_d3(D3);
-
-        Double4 D4 = s.get_d4();
-        if (D4.x != 1.0 || D4.y != 2.0 || D4.z != 3.0 || D4.w != 4.0) {
-            return false;
-        }
-        D4.x = 2.99;
-        D4.y = 3.99;
-        D4.z = 4.99;
-        D4.w = 5.99;
-        s.set_d4(D4);
-
-        Byte2 B2 = s.get_i8_2();
-        if (B2.x != 1 || B2.y != 2) {
-            return false;
-        }
-        B2.x = 2;
-        B2.y = 3;
-        s.set_i8_2(B2);
-
-        Byte3 B3 = s.get_i8_3();
-        if (B3.x != 1 || B3.y != 2 || B3.z != 3) {
-            return false;
-        }
-        B3.x = 2;
-        B3.y = 3;
-        B3.z = 4;
-        s.set_i8_3(B3);
-
-        Byte4 B4 = s.get_i8_4();
-        if (B4.x != 1 || B4.y != 2 || B4.z != 3 || B4.w != 4) {
-            return false;
-        }
-        B4.x = 2;
-        B4.y = 3;
-        B4.z = 4;
-        B4.w = 5;
-        s.set_i8_4(B4);
-
-        Short2 S2 = s.get_u8_2();
-        if (S2.x != 1 || S2.y != 2) {
-            return false;
-        }
-        S2.x = 2;
-        S2.y = 3;
-        s.set_u8_2(S2);
-
-        Short3 S3 = s.get_u8_3();
-        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
-            return false;
-        }
-        S3.x = 2;
-        S3.y = 3;
-        S3.z = 4;
-        s.set_u8_3(S3);
-
-        Short4 S4 = s.get_u8_4();
-        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
-            return false;
-        }
-        S4.x = 2;
-        S4.y = 3;
-        S4.z = 4;
-        S4.w = 5;
-        s.set_u8_4(S4);
-
-        S2 = s.get_i16_2();
-        if (S2.x != 1 || S2.y != 2) {
-            return false;
-        }
-        S2.x = 2;
-        S2.y = 3;
-        s.set_i16_2(S2);
-
-        S3 = s.get_i16_3();
-        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
-            return false;
-        }
-        S3.x = 2;
-        S3.y = 3;
-        S3.z = 4;
-        s.set_i16_3(S3);
-
-        S4 = s.get_i16_4();
-        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
-            return false;
-        }
-        S4.x = 2;
-        S4.y = 3;
-        S4.z = 4;
-        S4.w = 5;
-        s.set_i16_4(S4);
-
-        Int2 I2 = s.get_u16_2();
-        if (I2.x != 1 || I2.y != 2) {
-            return false;
-        }
-        I2.x = 2;
-        I2.y = 3;
-        s.set_u16_2(I2);
-
-        Int3 I3 = s.get_u16_3();
-        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
-            return false;
-        }
-        I3.x = 2;
-        I3.y = 3;
-        I3.z = 4;
-        s.set_u16_3(I3);
-
-        Int4 I4 = s.get_u16_4();
-        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
-            return false;
-        }
-        I4.x = 2;
-        I4.y = 3;
-        I4.z = 4;
-        I4.w = 5;
-        s.set_u16_4(I4);
-
-        I2 = s.get_i32_2();
-        if (I2.x != 1 || I2.y != 2) {
-            return false;
-        }
-        I2.x = 2;
-        I2.y = 3;
-        s.set_i32_2(I2);
-
-        I3 = s.get_i32_3();
-        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
-            return false;
-        }
-        I3.x = 2;
-        I3.y = 3;
-        I3.z = 4;
-        s.set_i32_3(I3);
-
-        I4 = s.get_i32_4();
-        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
-            return false;
-        }
-        I4.x = 2;
-        I4.y = 3;
-        I4.z = 4;
-        I4.w = 5;
-        s.set_i32_4(I4);
-
-        Long2 L2 = s.get_u32_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_u32_2(L2);
-
-        Long3 L3 = s.get_u32_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_u32_3(L3);
-
-        Long4 L4 = s.get_u32_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_u32_4(L4);
-
-        L2 = s.get_i64_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_i64_2(L2);
-
-        L3 = s.get_i64_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_i64_3(L3);
-
-        L4 = s.get_i64_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_i64_4(L4);
-
-        L2 = s.get_u64_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_u64_2(L2);
-
-        L3 = s.get_u64_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_u64_3(L3);
-
-        L4 = s.get_u64_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_u64_4(L4);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_vector s = new ScriptC_vector(pRS);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            failTest();
-        } else {
-            s.invoke_vector_test();
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
deleted file mode 100644
index fbac124..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test;
-import android.content.Context;
-import android.util.Log;
-import android.renderscript.RenderScript.RSMessageHandler;
-
-public class UnitTest extends Thread {
-    public String name;
-    private int result;
-    private ScriptField_ListAllocs_s.Item mItem;
-    private RSTestCore mRSTC;
-    private boolean msgHandled;
-    protected Context mCtx;
-
-    /* These constants must match those in shared.rsh */
-    public static final int RS_MSG_TEST_PASSED = 100;
-    public static final int RS_MSG_TEST_FAILED = 101;
-
-    private static int numTests = 0;
-    public int testID;
-
-    protected UnitTest(RSTestCore rstc, String n, int initResult, Context ctx) {
-        super();
-        mRSTC = rstc;
-        name = n;
-        msgHandled = false;
-        mCtx = ctx;
-        result = initResult;
-        testID = numTests++;
-    }
-
-    protected UnitTest(RSTestCore rstc, String n, Context ctx) {
-        this(rstc, n, 0, ctx);
-    }
-
-    protected UnitTest(RSTestCore rstc, Context ctx) {
-        this (rstc, "<Unknown>", ctx);
-    }
-
-    protected UnitTest(Context ctx) {
-        this (null, ctx);
-    }
-
-    protected void _RS_ASSERT(String message, boolean b) {
-        if(b == false) {
-            Log.e(name, message + " FAILED");
-            failTest();
-        }
-    }
-
-    private void updateUI() {
-        if (mItem != null) {
-            mItem.result = result;
-            msgHandled = true;
-            try {
-                mRSTC.refreshTestResults();
-            }
-            catch (IllegalStateException e) {
-                /* Ignore the case where our message receiver has been
-                   disconnected. This happens when we leave the application
-                   before it finishes running all of the unit tests. */
-            }
-        }
-    }
-
-    protected RSMessageHandler mRsMessage = new RSMessageHandler() {
-        public void run() {
-            if (result == 0) {
-                switch (mID) {
-                    case RS_MSG_TEST_PASSED:
-                        result = 1;
-                        break;
-                    case RS_MSG_TEST_FAILED:
-                        result = -1;
-                        break;
-                    default:
-                        RSTest.log("Unit test got unexpected message");
-                        return;
-                }
-            }
-
-            updateUI();
-        }
-    };
-
-    public void waitForMessage() {
-        while (!msgHandled) {
-            yield();
-        }
-    }
-
-    public int getResult() {
-        return result;
-    }
-
-    public void failTest() {
-        result = -1;
-        updateUI();
-    }
-
-    public void passTest() {
-        if (result != -1) {
-            result = 1;
-        }
-        updateUI();
-    }
-
-    public void setItem(ScriptField_ListAllocs_s.Item item) {
-        mItem = item;
-    }
-
-    public void run() {
-        /* This method needs to be implemented for each subclass */
-        if (mRSTC != null) {
-            mRSTC.refreshTestResults();
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
deleted file mode 100644
index 1b5e2ac..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/alloc.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "shared.rsh"
-
-int *a;
-int dimX;
-int dimY;
-int dimZ;
-
-rs_allocation aRaw;
-rs_allocation aFaces;
-rs_allocation aLOD;
-rs_allocation aFacesLOD;
-
-void root(int *o, uint32_t x, uint32_t y) {
-    *o = x + y * dimX;
-}
-
-static bool test_alloc_dims() {
-    bool failed = false;
-    int i, j;
-
-    _RS_ASSERT(rsAllocationGetDimX(aRaw) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aRaw) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aRaw) == dimZ);
-
-    // Test 2D addressing
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(aRaw, i, j);
-            int val = *(const int *)p;
-            _RS_ASSERT(val == (i + j * dimX));
-        }
-    }
-
-    // Test 1D addressing
-    for (i = 0; i < dimX; i++) {
-        rsDebug("Verifying ", i);
-        const void *p = rsGetElementAt(aRaw, i);
-        int val = *(const int *)p;
-        _RS_ASSERT(val == i);
-    }
-
-    // Test 3D addressing
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(aRaw, i, j, 0);
-            int val = *(const int *)p;
-            _RS_ASSERT(val == (i + j * dimX));
-        }
-    }
-
-    _RS_ASSERT(rsAllocationGetDimX(aFaces) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aFaces) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aFaces) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aFaces) != 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aFaces) == 0);
-
-    _RS_ASSERT(rsAllocationGetDimX(aLOD) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aLOD) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aLOD) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aLOD) == 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aLOD) != 0);
-
-    _RS_ASSERT(rsAllocationGetDimX(aFacesLOD) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aFacesLOD) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aFacesLOD) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aFacesLOD) != 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aFacesLOD) != 0);
-
-    if (failed) {
-        rsDebug("test_alloc_dims FAILED", 0);
-    }
-    else {
-        rsDebug("test_alloc_dims PASSED", 0);
-    }
-
-    return failed;
-}
-
-void alloc_test() {
-    bool failed = false;
-    failed |= test_alloc_dims();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_alloc.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_alloc.rs
deleted file mode 100644
index 74ffdb1..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_alloc.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "shared.rsh"
-
-const int dimX = 20;
-rs_allocation a[dimX];
-
-void array_alloc_test() {
-    bool failed = false;
-
-    for (int i = 0; i < dimX; i++) {
-        rsDebug("i: ", i);
-        _RS_ASSERT(rsAllocationGetDimX(a[i]) == 1);
-    }
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
deleted file mode 100644
index 842249a..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "shared.rsh"
-
-// Testing constant array initialization
-float fa[4] = {1.0, 9.9999f};
-double da[2] = {7.0, 8.88888};
-char ca[4] = {'a', 7, 'b', 'c'};
-short sa[4] = {1, 1, 2, 3};
-int ia[4] = {5, 8};
-long la[2] = {13, 21};
-long long lla[4] = {34};
-bool ba[3] = {true, false};
-
-void array_init_test() {
-    bool failed = false;
-
-    _RS_ASSERT(fa[0] == 1.0);
-    _RS_ASSERT(fa[1] == 9.9999f);
-    _RS_ASSERT(fa[2] == 0);
-    _RS_ASSERT(fa[3] == 0);
-
-    _RS_ASSERT(da[0] == 7.0);
-    _RS_ASSERT(da[1] == 8.88888);
-
-    _RS_ASSERT(ca[0] == 'a');
-    _RS_ASSERT(ca[1] == 7);
-    _RS_ASSERT(ca[2] == 'b');
-    _RS_ASSERT(ca[3] == 'c');
-
-    _RS_ASSERT(sa[0] == 1);
-    _RS_ASSERT(sa[1] == 1);
-    _RS_ASSERT(sa[2] == 2);
-    _RS_ASSERT(sa[3] == 3);
-
-    _RS_ASSERT(ia[0] == 5);
-    _RS_ASSERT(ia[1] == 8);
-    _RS_ASSERT(ia[2] == 0);
-    _RS_ASSERT(ia[3] == 0);
-
-    _RS_ASSERT(la[0] == 13);
-    _RS_ASSERT(la[1] == 21);
-
-    _RS_ASSERT(lla[0] == 34);
-    _RS_ASSERT(lla[1] == 0);
-    _RS_ASSERT(lla[2] == 0);
-    _RS_ASSERT(lla[3] == 0);
-
-    _RS_ASSERT(ba[0] == true);
-    _RS_ASSERT(ba[1] == false);
-    _RS_ASSERT(ba[2] == false);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs
deleted file mode 100644
index f0a5041..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "shared.rsh"
-
-// Testing atomic operations
-static bool testUMax(uint32_t dst, uint32_t src) {
-    bool failed = false;
-    uint32_t old = dst;
-    uint32_t expect = (dst > src ? dst : src);
-    uint32_t ret = rsAtomicMax(&dst, src);
-    _RS_ASSERT(old == ret);
-    _RS_ASSERT(dst == expect);
-    return failed;
-}
-
-static bool testUMin(uint32_t dst, uint32_t src) {
-    bool failed = false;
-    uint32_t old = dst;
-    uint32_t expect = (dst < src ? dst : src);
-    uint32_t ret = rsAtomicMin(&dst, src);
-    _RS_ASSERT(old == ret);
-    _RS_ASSERT(dst == expect);
-    return failed;
-}
-
-static bool testUCas(uint32_t dst, uint32_t cmp, uint32_t swp) {
-    bool failed = false;
-    uint32_t old = dst;
-    uint32_t expect = (dst == cmp ? swp : dst);
-    uint32_t ret = rsAtomicCas(&dst, cmp, swp);
-    _RS_ASSERT(old == ret);
-    _RS_ASSERT(dst == expect);
-    return failed;
-}
-
-static bool test_atomics() {
-    bool failed = false;
-
-    failed |= testUMax(5, 6);
-    failed |= testUMax(6, 5);
-    failed |= testUMax(5, 0xf0000006);
-    failed |= testUMax(0xf0000006, 5);
-
-    failed |= testUMin(5, 6);
-    failed |= testUMin(6, 5);
-    failed |= testUMin(5, 0xf0000006);
-    failed |= testUMin(0xf0000006, 5);
-
-    failed |= testUCas(4, 4, 5);
-    failed |= testUCas(4, 5, 5);
-    failed |= testUCas(5, 5, 4);
-    failed |= testUCas(5, 4, 4);
-    failed |= testUCas(0xf0000004, 0xf0000004, 0xf0000005);
-    failed |= testUCas(0xf0000004, 0xf0000005, 0xf0000005);
-    failed |= testUCas(0xf0000005, 0xf0000005, 0xf0000004);
-    failed |= testUCas(0xf0000005, 0xf0000004, 0xf0000004);
-
-    if (failed) {
-        rsDebug("test_atomics FAILED", 0);
-    }
-    else {
-        rsDebug("test_atomics PASSED", 0);
-    }
-
-    return failed;
-}
-
-void atomic_test() {
-    bool failed = false;
-    failed |= test_atomics();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/bug_char.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/bug_char.rs
deleted file mode 100644
index dcd7b72..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/bug_char.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "shared.rsh"
-
-char rand_sc1_0, rand_sc1_1;
-char2 rand_sc2_0, rand_sc2_1;
-
-char min_rand_sc1_sc1;
-char2 min_rand_sc2_sc2;
-
-static bool test_bug_char() {
-    bool failed = false;
-
-    rsDebug("rand_sc2_0.x: ", rand_sc2_0.x);
-    rsDebug("rand_sc2_0.y: ", rand_sc2_0.y);
-    rsDebug("rand_sc2_1.x: ", rand_sc2_1.x);
-    rsDebug("rand_sc2_1.y: ", rand_sc2_1.y);
-    char temp_sc1;
-    char2 temp_sc2;
-
-    temp_sc1 = min( rand_sc1_0, rand_sc1_1 );
-    if (temp_sc1 != min_rand_sc1_sc1) {
-        rsDebug("temp_sc1", temp_sc1);
-        failed = true;
-    }
-    rsDebug("broken", 'y');
-
-    temp_sc2 = min( rand_sc2_0, rand_sc2_1 );
-    if (temp_sc2.x != min_rand_sc2_sc2.x
-            || temp_sc2.y != min_rand_sc2_sc2.y) {
-        failed = true;
-    }
-
-
-    return failed;
-}
-
-void bug_char_test() {
-    bool failed = false;
-    failed |= test_bug_char();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/clamp.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/clamp.rs
deleted file mode 100644
index 28b00bd..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/clamp.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "shared.rsh"
-
-static bool test_clamp_vector() {
-    bool failed = false;
-
-    float2 src2 = { 2.0f, 2.0f};
-    float2 min2 = { 0.5f, -3.0f};
-    float2 max2 = { 1.0f, 9.0f};
-
-    float2 res2 = clamp(src2, min2, max2);
-    _RS_ASSERT(res2.x == 1.0f);
-    _RS_ASSERT(res2.y == 2.0f);
-
-
-    float3 src3 = { 2.0f, 2.0f, 1.0f};
-    float3 min3 = { 0.5f, -3.0f, 3.0f};
-    float3 max3 = { 1.0f, 9.0f, 4.0f};
-
-    float3 res3 = clamp(src3, min3, max3);
-    _RS_ASSERT(res3.x == 1.0f);
-    _RS_ASSERT(res3.y == 2.0f);
-    _RS_ASSERT(res3.z == 3.0f);
-
-
-    float4 src4 = { 2.0f, 2.0f, 1.0f, 4.0f };
-    float4 min4 = { 0.5f, -3.0f, 3.0f, 4.0f };
-    float4 max4 = { 1.0f, 9.0f, 4.0f, 4.0f };
-
-    float4 res4 = clamp(src4, min4, max4);
-    _RS_ASSERT(res4.x == 1.0f);
-    _RS_ASSERT(res4.y == 2.0f);
-    _RS_ASSERT(res4.z == 3.0f);
-    _RS_ASSERT(res4.w == 4.0f);
-
-    if (failed) {
-        rsDebug("test_clamp_vector FAILED", 0);
-    }
-    else {
-        rsDebug("test_clamp_vector PASSED", 0);
-    }
-
-    return failed;
-}
-
-void clamp_test() {
-    bool failed = false;
-    failed |= test_clamp_vector();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/clamp_relaxed.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/clamp_relaxed.rs
deleted file mode 100644
index 71c65ae..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/clamp_relaxed.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "clamp.rs"
-#pragma rs_fp_relaxed
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
deleted file mode 100644
index 732eaef..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "shared.rsh"
-
-const float floatTest = 1.99f;
-const double doubleTest = 2.05;
-const char charTest = -8;
-const short shortTest = -16;
-const int intTest = -32;
-const long longTest = 17179869184l; // 1 << 34
-const long long longlongTest = 68719476736l; // 1 << 36
-
-const uchar ucharTest = 8;
-const ushort ushortTest = 16;
-const uint uintTest = 32;
-const ulong ulongTest = 4611686018427387904L;
-const int64_t int64_tTest = -17179869184l; // - 1 << 34
-const uint64_t uint64_tTest = 117179869184l;
-
-const bool boolTest = true;
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/convert.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/convert.rs
deleted file mode 100644
index e314f2b..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/convert.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "shared.rsh"
-
-float4 f4 = { 2.0f, 4.0f, 6.0f, 8.0f };
-
-char4 i8_4 = { -1, -2, -3, 4 };
-
-static bool test_convert() {
-    bool failed = false;
-
-    f4 = convert_float4(i8_4);
-    _RS_ASSERT(f4.x == -1.0f);
-    _RS_ASSERT(f4.y == -2.0f);
-    _RS_ASSERT(f4.z == -3.0f);
-    _RS_ASSERT(f4.w == 4.0f);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-void convert_test() {
-    bool failed = false;
-    failed |= test_convert();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/convert_relaxed.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/convert_relaxed.rs
deleted file mode 100644
index 81abb9b..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/convert_relaxed.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "convert.rs"
-#pragma rs_fp_relaxed
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/copy_test.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/copy_test.rs
deleted file mode 100644
index f4243eb..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/copy_test.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-
-#include "shared.rsh"
-
-void sendResult(bool pass) {
-    if (pass) {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-}
-
-
-float2 __attribute((kernel)) copyFloat2(float2 i) {
-    return i;
-}
-
-float3 __attribute((kernel)) copyFloat3(float3 i) {
-    return i;
-}
-
-float4 __attribute((kernel)) copyFloat4(float4 i) {
-    return i;
-}
-
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
deleted file mode 100644
index 419ce07..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_element simpleElem;
-rs_element complexElem;
-typedef struct ComplexStruct {
-    float subElem0;
-    float subElem1;
-    int subElem2;
-    float arrayElem0[2];
-    int arrayElem1[5];
-    char subElem3;
-    float subElem4;
-    float2 subElem5;
-    float3 subElem6;
-    float4 subElem_7;
-} ComplexStruct_t;
-
-ComplexStruct_t *complexStruct;
-
-static const char *subElemNames[] = {
-    "subElem0",
-    "subElem1",
-    "subElem2",
-    "arrayElem0",
-    "arrayElem1",
-    "subElem3",
-    "subElem4",
-    "subElem5",
-    "subElem6",
-    "subElem_7",
-};
-
-static uint32_t subElemNamesSizes[] = {
-    8,
-    8,
-    8,
-    10,
-    10,
-    8,
-    8,
-    8,
-    8,
-    9,
-};
-
-static uint32_t subElemArraySizes[] = {
-    1,
-    1,
-    1,
-    2,
-    5,
-    1,
-    1,
-    1,
-    1,
-    1,
-};
-
-static void resetStruct() {
-    uint8_t *bytePtr = (uint8_t*)complexStruct;
-    uint32_t sizeOfStruct = sizeof(*complexStruct);
-    for(uint32_t i = 0; i < sizeOfStruct; i ++) {
-        bytePtr[i] = 0;
-    }
-}
-
-static bool equals(const char *name0, const char * name1, uint32_t len) {
-    for (uint32_t i = 0; i < len; i ++) {
-        if (name0[i] != name1[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-static bool test_element_getters() {
-    bool failed = false;
-
-    uint32_t subElemOffsets[10];
-    uint32_t index = 0;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6   - (uint32_t)complexStruct;
-    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7  - (uint32_t)complexStruct;
-
-    uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
-    _RS_ASSERT(subElemCount == 0);
-    _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER);
-    _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
-    _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3);
-
-    subElemCount = rsElementGetSubElementCount(complexElem);
-    _RS_ASSERT(subElemCount == 10);
-    _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
-    _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
-    _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
-    _RS_ASSERT(rsElementGetBytesSize(complexElem) == sizeof(*complexStruct));
-
-    char buffer[64];
-    for (uint32_t i = 0; i < subElemCount; i ++) {
-        rs_element subElem = rsElementGetSubElement(complexElem, i);
-        _RS_ASSERT(rsIsObject(subElem));
-
-        _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
-
-        uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
-        _RS_ASSERT(written == subElemNamesSizes[i]);
-        _RS_ASSERT(equals(buffer, subElemNames[i], written));
-
-        _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
-        _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
-    }
-
-    // Tests error checking
-    rs_element subElem = rsElementGetSubElement(complexElem, subElemCount);
-    _RS_ASSERT(!rsIsObject(subElem));
-
-    _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0);
-
-    _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0);
-    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0);
-    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0);
-    uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5);
-    _RS_ASSERT(written == 4);
-    _RS_ASSERT(buffer[4] == '\0');
-
-    _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0);
-    _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0);
-
-    if (failed) {
-        rsDebug("test_element_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_element_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void element_test() {
-    bool failed = false;
-    failed |= test_element_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
deleted file mode 100644
index 08e6bed..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "shared.rsh"
-
-rs_allocation aRaw;
-int dimX;
-int dimY;
-static bool failed = false;
-
-void root(int *out, uint32_t x, uint32_t y) {
-    *out = x + y * dimX;
-}
-
-void foo(const int *in, int *out, uint32_t x, uint32_t y) {
-    _RS_ASSERT(*in == (x + y * dimX));
-    *out = 99 + x + y * dimX;
-    _RS_ASSERT(*out == (99 + x + y * dimX));
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            _RS_ASSERT(v == (i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-static bool test_foo_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            _RS_ASSERT(v == (99 + i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_foo_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_foo_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void verify_foo() {
-    failed |= test_foo_output();
-}
-
-void foreach_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
deleted file mode 100644
index fa76390..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/foreach_bounds.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "shared.rsh"
-
-int dimX;
-int dimY;
-int xStart = 0;
-int xEnd = 0;
-int yStart = 0;
-int yEnd = 0;
-
-static bool failed = false;
-
-rs_script s;
-rs_allocation aRaw;
-rs_allocation ain;
-rs_allocation aout;
-
-void root(int *out, uint32_t x, uint32_t y) {
-    *out = x + y * dimX;
-}
-
-int __attribute__((kernel)) zero() {
-    return 0;
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            if (i < xStart || i >= xEnd || j < yStart || j >= yEnd) {
-                _RS_ASSERT(v == 0);
-            } else {
-                _RS_ASSERT(v == (i + j * dimX));
-            }
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void foreach_bounds_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/fp_mad.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/fp_mad.rs
deleted file mode 100644
index b6f2b2a6..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/fp_mad.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "shared.rsh"
-
-const int TEST_COUNT = 1;
-
-static float data_f1[1025];
-static float4 data_f4[1025];
-
-static void test_mad4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 80); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = (data_f4[i] * 0.02f +
-                          data_f4[i+1] * 0.04f +
-                          data_f4[i+2] * 0.05f +
-                          data_f4[i+3] * 0.1f +
-                          data_f4[i+4] * 0.2f +
-                          data_f4[i+5] * 0.2f +
-                          data_f4[i+6] * 0.1f +
-                          data_f4[i+7] * 0.05f +
-                          data_f4[i+8] * 0.04f +
-                          data_f4[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad4 M ops", 1000.f / time);
-}
-
-static void test_mad(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 20); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = (data_f1[i] * 0.02f +
-                          data_f1[i+1] * 0.04f +
-                          data_f1[i+2] * 0.05f +
-                          data_f1[i+3] * 0.1f +
-                          data_f1[i+4] * 0.2f +
-                          data_f1[i+5] * 0.2f +
-                          data_f1[i+6] * 0.1f +
-                          data_f1[i+7] * 0.05f +
-                          data_f1[i+8] * 0.04f +
-                          data_f1[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad M ops", 1000.f / time);
-}
-
-static void test_norm(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = normalize(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_norm M ops", 10.f / time);
-}
-
-static void test_sincos4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10 / 4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = sin(data_f4[i]) * cos(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos4 M ops", 10.f / time);
-}
-
-static void test_sincos(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = sin(data_f1[i]) * cos(data_f1[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos M ops", 10.f / time);
-}
-
-static void test_clamp(uint32_t index) {
-    start();
-
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp M ops", 100.f / time);
-
-    start();
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            if (data_f1[i] < -1.f) data_f1[i] = -1.f;
-            if (data_f1[i] > -1.f) data_f1[i] = 1.f;
-        }
-    }
-
-    time = end(index);
-    rsDebug("fp_clamp ref M ops", 100.f / time);
-}
-
-static void test_clamp4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100 /4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp4 M ops", 100.f / time);
-}
-
-void fp_mad_test(uint32_t index, int test_num) {
-    int x;
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f;
-        data_f4[x].x = (x & 0xf) * 0.1f;
-        data_f4[x].y = (x & 0xf0) * 0.1f;
-        data_f4[x].z = (x & 0x33) * 0.1f;
-        data_f4[x].w = (x & 0x77) * 0.1f;
-    }
-
-    test_mad4(index);
-    test_mad(index);
-
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].x = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].y = (x & 0xf0) * 0.1f + 1.f;
-        data_f4[x].z = (x & 0x33) * 0.1f + 1.f;
-        data_f4[x].w = (x & 0x77) * 0.1f + 1.f;
-    }
-
-    test_norm(index);
-    test_sincos4(index);
-    test_sincos(index);
-    test_clamp4(index);
-    test_clamp(index);
-
-    // TODO Actually verify test result accuracy
-    rsDebug("fp_mad_test PASSED", 0);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/int4.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/int4.rs
deleted file mode 100644
index c791cab..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/int4.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "shared.rsh"
-#pragma rs_fp_relaxed
-
-uchar4 u4 = 4;
-int4 gi4 = {2, 2, 2, 2};
-
-void int4_test() {
-    bool failed = false;
-    int4 i4 = {u4.x, u4.y, u4.z, u4.w};
-    i4 *= gi4;
-
-    rsDebug("i4.x", i4.x);
-    rsDebug("i4.y", i4.y);
-    rsDebug("i4.z", i4.z);
-    rsDebug("i4.w", i4.w);
-
-    _RS_ASSERT(i4.x == 8);
-    _RS_ASSERT(i4.y == 8);
-    _RS_ASSERT(i4.z == 8);
-    _RS_ASSERT(i4.w == 8);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/kernel.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/kernel.rs
deleted file mode 100644
index d6c9df3..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/kernel.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "shared.rsh"
-
-int *ain;
-int *aout;
-int dimX;
-static bool failed = false;
-
-void init_vars(int *out) {
-    *out = 7;
-}
-
-
-int __attribute__((kernel)) root(int ain, uint32_t x) {
-    _RS_ASSERT(ain == 7);
-    return ain + x;
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i;
-
-    for (i = 0; i < dimX; i++) {
-        _RS_ASSERT(aout[i] == (i + ain[i]));
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void kernel_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/kernel_struct.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/kernel_struct.rs
deleted file mode 100644
index 62c30ae..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/kernel_struct.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "shared.rsh"
-
-struct simpleStruct {
-    int i1;
-    char ignored1;
-    float f1;
-    int i2;
-    char ignored2;
-    float f2;
-};
-
-struct simpleStruct *ain;
-struct simpleStruct *aout;
-int dimX;
-static bool failed = false;
-
-void init_vars(struct simpleStruct *out, uint32_t x) {
-    out->i1 = 0;
-    out->f1 = 0.f;
-    out->i2 = 1;
-    out->f2 = 1.0f;
-}
-
-struct simpleStruct __attribute__((kernel))
-        root(struct simpleStruct in, uint32_t x) {
-    struct simpleStruct s;
-    s.i1 = in.i1 + x;
-    s.f1 = in.f1 + x;
-    s.i2 = in.i2 + x;
-    s.f2 = in.f2 + x;
-    return s;
-}
-
-static bool test_root_output() {
-    bool failed = false;
-    int i;
-
-    for (i = 0; i < dimX; i++) {
-        _RS_ASSERT(aout[i].i1 == (i + ain[i].i1));
-        _RS_ASSERT(aout[i].f1 == (i + ain[i].f1));
-        _RS_ASSERT(aout[i].i2 == (i + ain[i].i2));
-        _RS_ASSERT(aout[i].f2 == (i + ain[i].f2));
-    }
-
-    if (failed) {
-        rsDebug("test_root_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_root_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_root() {
-    failed |= test_root_output();
-}
-
-void kernel_struct_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
deleted file mode 100644
index edde9d8..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/math.rs
+++ /dev/null
@@ -1,437 +0,0 @@
-#include "shared.rsh"
-
-// Testing math library
-
-volatile float f1;
-volatile float2 f2;
-volatile float3 f3;
-volatile float4 f4;
-
-volatile int i1;
-volatile int2 i2;
-volatile int3 i3;
-volatile int4 i4;
-
-volatile uint ui1;
-volatile uint2 ui2;
-volatile uint3 ui3;
-volatile uint4 ui4;
-
-volatile short s1;
-volatile short2 s2;
-volatile short3 s3;
-volatile short4 s4;
-
-volatile ushort us1;
-volatile ushort2 us2;
-volatile ushort3 us3;
-volatile ushort4 us4;
-
-volatile char c1;
-volatile char2 c2;
-volatile char3 c3;
-volatile char4 c4;
-
-volatile uchar uc1;
-volatile uchar2 uc2;
-volatile uchar3 uc3;
-volatile uchar4 uc4;
-
-#define DECL_INT(prefix)            \
-volatile char prefix##_c_1 = 1;     \
-volatile char2 prefix##_c_2 = 1;    \
-volatile char3 prefix##_c_3 = 1;    \
-volatile char4 prefix##_c_4 = 1;    \
-volatile uchar prefix##_uc_1 = 1;   \
-volatile uchar2 prefix##_uc_2 = 1;  \
-volatile uchar3 prefix##_uc_3 = 1;  \
-volatile uchar4 prefix##_uc_4 = 1;  \
-volatile short prefix##_s_1 = 1;    \
-volatile short2 prefix##_s_2 = 1;   \
-volatile short3 prefix##_s_3 = 1;   \
-volatile short4 prefix##_s_4 = 1;   \
-volatile ushort prefix##_us_1 = 1;  \
-volatile ushort2 prefix##_us_2 = 1; \
-volatile ushort3 prefix##_us_3 = 1; \
-volatile ushort4 prefix##_us_4 = 1; \
-volatile int prefix##_i_1 = 1;      \
-volatile int2 prefix##_i_2 = 1;     \
-volatile int3 prefix##_i_3 = 1;     \
-volatile int4 prefix##_i_4 = 1;     \
-volatile uint prefix##_ui_1 = 1;    \
-volatile uint2 prefix##_ui_2 = 1;   \
-volatile uint3 prefix##_ui_3 = 1;   \
-volatile uint4 prefix##_ui_4 = 1;   \
-volatile long prefix##_l_1 = 1;     \
-volatile ulong prefix##_ul_1 = 1;
-
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
-
-#define TEST_INT_OP_TYPE(op, type)                      \
-rsDebug("Testing " #op " for " #type "1", i++);         \
-res_##type##_1 = src1_##type##_1 op src2_##type##_1;    \
-rsDebug("Testing " #op " for " #type "2", i++);         \
-res_##type##_2 = src1_##type##_2 op src2_##type##_2;    \
-rsDebug("Testing " #op " for " #type "3", i++);         \
-res_##type##_3 = src1_##type##_3 op src2_##type##_3;    \
-rsDebug("Testing " #op " for " #type "4", i++);         \
-res_##type##_4 = src1_##type##_4 op src2_##type##_4;
-
-#define TEST_INT_OP(op)                     \
-TEST_INT_OP_TYPE(op, c)                     \
-TEST_INT_OP_TYPE(op, uc)                    \
-TEST_INT_OP_TYPE(op, s)                     \
-TEST_INT_OP_TYPE(op, us)                    \
-TEST_INT_OP_TYPE(op, i)                     \
-TEST_INT_OP_TYPE(op, ui)                    \
-rsDebug("Testing " #op " for l1", i++);     \
-res_l_1 = src1_l_1 op src2_l_1;             \
-rsDebug("Testing " #op " for ul1", i++);    \
-res_ul_1 = src1_ul_1 op src2_ul_1;
-
-#define TEST_XN_FUNC_YN(typeout, fnc, typein)   \
-    res_##typeout##_1 = fnc(src1_##typein##_1); \
-    res_##typeout##_2 = fnc(src1_##typein##_2); \
-    res_##typeout##_3 = fnc(src1_##typein##_3); \
-    res_##typeout##_4 = fnc(src1_##typein##_4);
-
-#define TEST_XN_FUNC_XN_XN(type, fnc)                       \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1); \
-    res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2); \
-    res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3); \
-    res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4);
-
-#define TEST_X_FUNC_X_X_X(type, fnc)    \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src2_##type##_1);
-
-#define TEST_IN_FUNC_IN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, uc)    \
-    TEST_XN_FUNC_YN(c, fnc, c)      \
-    TEST_XN_FUNC_YN(us, fnc, us)    \
-    TEST_XN_FUNC_YN(s, fnc, s)      \
-    TEST_XN_FUNC_YN(ui, fnc, ui)    \
-    TEST_XN_FUNC_YN(i, fnc, i)
-
-#define TEST_UIN_FUNC_IN(fnc)       \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, c)     \
-    TEST_XN_FUNC_YN(us, fnc, s)     \
-    TEST_XN_FUNC_YN(ui, fnc, i)     \
-
-#define TEST_IN_FUNC_IN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_XN_XN(uc, fnc)     \
-    TEST_XN_FUNC_XN_XN(c, fnc)      \
-    TEST_XN_FUNC_XN_XN(us, fnc)     \
-    TEST_XN_FUNC_XN_XN(s, fnc)      \
-    TEST_XN_FUNC_XN_XN(ui, fnc)     \
-    TEST_XN_FUNC_XN_XN(i, fnc)
-
-#define TEST_I_FUNC_I_I_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_X_FUNC_X_X_X(uc, fnc)      \
-    TEST_X_FUNC_X_X_X(c, fnc)       \
-    TEST_X_FUNC_X_X_X(us, fnc)      \
-    TEST_X_FUNC_X_X_X(s, fnc)       \
-    TEST_X_FUNC_X_X_X(ui, fnc)      \
-    TEST_X_FUNC_X_X_X(i, fnc)
-
-#define TEST_FN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f2 = fnc(f2);                   \
-    f3 = fnc(f3);                   \
-    f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (float*) &f1);     \
-    f2 = fnc(f2, (float2*) &f2);    \
-    f3 = fnc(f3, (float3*) &f3);    \
-    f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f2);               \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_F34_FUNC_F34_F34(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f1);               \
-    f3 = fnc(f3, f1);               \
-    f4 = fnc(f4, f1);
-
-#define TEST_F_FUNC_FN(fnc)         \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f1 = fnc(f2);                   \
-    f1 = fnc(f3);                   \
-    f1 = fnc(f4);
-
-#define TEST_F_FUNC_FN_FN(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f1 = fnc(f2, f2);               \
-    f1 = fnc(f3, f3);               \
-    f1 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i2);               \
-    f3 = fnc(f3, i3);               \
-    f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i1);               \
-    f3 = fnc(f3, i1);               \
-    f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f2, f2);           \
-    f3 = fnc(f3, f3, f3);           \
-    f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_FN_F(fnc)   \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f1, f1);           \
-    f3 = fnc(f3, f1, f1);           \
-    f4 = fnc(f4, f1, f1);
-
-#define TEST_FN_FUNC_FN_PIN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (int*) &i1);       \
-    f2 = fnc(f2, (int2*) &i2);      \
-    f3 = fnc(f3, (int3*) &i3);      \
-    f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, (int*) &i1);   \
-    f2 = fnc(f2, f2, (int2*) &i2);  \
-    f3 = fnc(f3, f3, (int3*) &i3);  \
-    f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    i1 = fnc(f1);                   \
-    i2 = fnc(f2);                   \
-    i3 = fnc(f3);                   \
-    i4 = fnc(f4);
-
-static bool test_fp_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_FN_FUNC_FN(acos);
-    TEST_FN_FUNC_FN(acosh);
-    TEST_FN_FUNC_FN(acospi);
-    TEST_FN_FUNC_FN(asin);
-    TEST_FN_FUNC_FN(asinh);
-    TEST_FN_FUNC_FN(asinpi);
-    TEST_FN_FUNC_FN(atan);
-    TEST_FN_FUNC_FN_FN(atan2);
-    TEST_FN_FUNC_FN(atanh);
-    TEST_FN_FUNC_FN(atanpi);
-    TEST_FN_FUNC_FN_FN(atan2pi);
-    TEST_FN_FUNC_FN(cbrt);
-    TEST_FN_FUNC_FN(ceil);
-    TEST_FN_FUNC_FN_FN_FN(clamp);
-    TEST_FN_FUNC_FN_FN_F(clamp);
-    TEST_FN_FUNC_FN_FN(copysign);
-    TEST_FN_FUNC_FN(cos);
-    TEST_FN_FUNC_FN(cosh);
-    TEST_FN_FUNC_FN(cospi);
-    TEST_F34_FUNC_F34_F34(cross);
-    TEST_FN_FUNC_FN(degrees);
-    TEST_F_FUNC_FN_FN(distance);
-    TEST_F_FUNC_FN_FN(dot);
-    TEST_FN_FUNC_FN(erfc);
-    TEST_FN_FUNC_FN(erf);
-    TEST_FN_FUNC_FN(exp);
-    TEST_FN_FUNC_FN(exp2);
-    TEST_FN_FUNC_FN(exp10);
-    TEST_FN_FUNC_FN(expm1);
-    TEST_FN_FUNC_FN(fabs);
-    TEST_FN_FUNC_FN_FN(fdim);
-    TEST_FN_FUNC_FN(floor);
-    TEST_FN_FUNC_FN_FN_FN(fma);
-    TEST_FN_FUNC_FN_FN(fmax);
-    TEST_FN_FUNC_FN_F(fmax);
-    TEST_FN_FUNC_FN_FN(fmin);
-    TEST_FN_FUNC_FN_F(fmin);
-    TEST_FN_FUNC_FN_FN(fmod);
-    TEST_FN_FUNC_FN_PFN(fract);
-    TEST_FN_FUNC_FN(fract);
-    TEST_FN_FUNC_FN_PIN(frexp);
-    TEST_FN_FUNC_FN_FN(hypot);
-    TEST_IN_FUNC_FN(ilogb);
-    TEST_FN_FUNC_FN_IN(ldexp);
-    TEST_FN_FUNC_FN_I(ldexp);
-    TEST_F_FUNC_FN(length);
-    TEST_FN_FUNC_FN(lgamma);
-    TEST_FN_FUNC_FN_PIN(lgamma);
-    TEST_FN_FUNC_FN(log);
-    TEST_FN_FUNC_FN(log2);
-    TEST_FN_FUNC_FN(log10);
-    TEST_FN_FUNC_FN(log1p);
-    TEST_FN_FUNC_FN(logb);
-    TEST_FN_FUNC_FN_FN_FN(mad);
-    TEST_FN_FUNC_FN_FN(max);
-    TEST_FN_FUNC_FN_F(max);
-    TEST_FN_FUNC_FN_FN(min);
-    TEST_FN_FUNC_FN_F(min);
-    TEST_FN_FUNC_FN_FN_FN(mix);
-    TEST_FN_FUNC_FN_FN_F(mix);
-    TEST_FN_FUNC_FN_PFN(modf);
-    // nan
-    TEST_FN_FUNC_FN_FN(nextafter);
-    TEST_FN_FUNC_FN(normalize);
-    TEST_FN_FUNC_FN_FN(pow);
-    TEST_FN_FUNC_FN_IN(pown);
-    TEST_FN_FUNC_FN_FN(powr);
-    TEST_FN_FUNC_FN(radians);
-    TEST_FN_FUNC_FN_FN(remainder);
-    TEST_FN_FUNC_FN_FN_PIN(remquo);
-    TEST_FN_FUNC_FN(rint);
-    TEST_FN_FUNC_FN_IN(rootn);
-    TEST_FN_FUNC_FN(round);
-    TEST_FN_FUNC_FN(rsqrt);
-    TEST_FN_FUNC_FN(sign);
-    TEST_FN_FUNC_FN(sin);
-    TEST_FN_FUNC_FN_PFN(sincos);
-    TEST_FN_FUNC_FN(sinh);
-    TEST_FN_FUNC_FN(sinpi);
-    TEST_FN_FUNC_FN(sqrt);
-    TEST_FN_FUNC_FN_FN(step);
-    TEST_FN_FUNC_FN_F(step);
-    TEST_FN_FUNC_FN(tan);
-    TEST_FN_FUNC_FN(tanh);
-    TEST_FN_FUNC_FN(tanpi);
-    TEST_FN_FUNC_FN(tgamma);
-    TEST_FN_FUNC_FN(trunc);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_fp_math FAILED", time);
-    }
-    else {
-        rsDebug("test_fp_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_int_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_UIN_FUNC_IN(abs);
-    TEST_IN_FUNC_IN(clz);
-    TEST_IN_FUNC_IN_IN(min);
-    TEST_IN_FUNC_IN_IN(max);
-    TEST_I_FUNC_I_I_I(rsClamp);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_int_math FAILED", time);
-    }
-    else {
-        rsDebug("test_int_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_basic_operators() {
-    bool failed = false;
-    int i = 0;
-
-    TEST_INT_OP(+);
-    TEST_INT_OP(-);
-    TEST_INT_OP(*);
-    TEST_INT_OP(/);
-    TEST_INT_OP(%);
-    TEST_INT_OP(<<);
-    TEST_INT_OP(>>);
-
-    if (failed) {
-        rsDebug("test_basic_operators FAILED", 0);
-    }
-    else {
-        rsDebug("test_basic_operators PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define TEST_CVT(to, from, type)                        \
-rsDebug("Testing convert from " #from " to " #to, 0);   \
-to##1 = from##1;                                        \
-to##2 = convert_##type##2(from##2);                     \
-to##3 = convert_##type##3(from##3);                     \
-to##4 = convert_##type##4(from##4);
-
-#define TEST_CVT_MATRIX(to, type)   \
-TEST_CVT(to, c, type);              \
-TEST_CVT(to, uc, type);             \
-TEST_CVT(to, s, type);              \
-TEST_CVT(to, us, type);             \
-TEST_CVT(to, i, type);              \
-TEST_CVT(to, ui, type);             \
-TEST_CVT(to, f, type);              \
-
-static bool test_convert() {
-    bool failed = false;
-
-    TEST_CVT_MATRIX(c, char);
-    TEST_CVT_MATRIX(uc, uchar);
-    TEST_CVT_MATRIX(s, short);
-    TEST_CVT_MATRIX(us, ushort);
-    TEST_CVT_MATRIX(i, int);
-    TEST_CVT_MATRIX(ui, uint);
-    TEST_CVT_MATRIX(f, float);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_convert();
-    failed |= test_fp_math(index);
-    failed |= test_int_math(index);
-    failed |= test_basic_operators();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs
deleted file mode 100644
index 5bfbb2b..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/math_agree.rs
+++ /dev/null
@@ -1,409 +0,0 @@
-#include "shared.rsh"
-//#pragma rs_fp_relaxed
-
-volatile float x = 0.0f;
-volatile float y = 0.0f;
-volatile float result_add = 0.0f;
-volatile float result_sub = 0.0f;
-volatile float result_mul = 0.0f;
-volatile float result_div = 0.0f;
-
-#define DECLARE_INPUT_SET(type, abbrev)         \
-volatile type    rand_##abbrev##1_0, rand_##abbrev##1_1; \
-volatile type##2 rand_##abbrev##2_0, rand_##abbrev##2_1; \
-volatile type##3 rand_##abbrev##3_0, rand_##abbrev##3_1; \
-volatile type##4 rand_##abbrev##4_0, rand_##abbrev##4_1;
-
-#define DECLARE_ALL_INPUT_SETS()    \
-DECLARE_INPUT_SET(float, f);        \
-DECLARE_INPUT_SET(char, sc);        \
-DECLARE_INPUT_SET(uchar, uc);       \
-DECLARE_INPUT_SET(short, ss);       \
-DECLARE_INPUT_SET(ushort, us);      \
-DECLARE_INPUT_SET(int, si);         \
-DECLARE_INPUT_SET(uint, ui);        \
-DECLARE_INPUT_SET(long, sl);        \
-DECLARE_INPUT_SET(ulong, ul);
-
-DECLARE_ALL_INPUT_SETS();
-
-#define DECLARE_REFERENCE_SET_VEC_VEC(type, abbrev, func)   \
-volatile type    func##_rand_##abbrev##1_##abbrev##1;                \
-volatile type##2 func##_rand_##abbrev##2_##abbrev##2;                \
-volatile type##3 func##_rand_##abbrev##3_##abbrev##3;                \
-volatile type##4 func##_rand_##abbrev##4_##abbrev##4;
-#define DECLARE_REFERENCE_SET_VEC_SCL(type, abbrev, func)   \
-volatile type##2 func##_rand_##abbrev##2_##abbrev##1;                \
-volatile type##3 func##_rand_##abbrev##3_##abbrev##1;                \
-volatile type##4 func##_rand_##abbrev##4_##abbrev##1;
-
-#define DECLARE_ALL_REFERENCE_SETS_VEC_VEC(func)    \
-DECLARE_REFERENCE_SET_VEC_VEC(float, f, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(char, sc, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(uchar, uc, func);     \
-DECLARE_REFERENCE_SET_VEC_VEC(short, ss, func);     \
-DECLARE_REFERENCE_SET_VEC_VEC(ushort, us, func);    \
-DECLARE_REFERENCE_SET_VEC_VEC(int, si, func);       \
-DECLARE_REFERENCE_SET_VEC_VEC(uint, ui, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(long, sl, func);      \
-DECLARE_REFERENCE_SET_VEC_VEC(ulong, ul, func);
-
-DECLARE_ALL_REFERENCE_SETS_VEC_VEC(min);
-DECLARE_ALL_REFERENCE_SETS_VEC_VEC(max);
-DECLARE_REFERENCE_SET_VEC_VEC(float, f, fmin);
-DECLARE_REFERENCE_SET_VEC_SCL(float, f, fmin);
-DECLARE_REFERENCE_SET_VEC_VEC(float, f, fmax);
-DECLARE_REFERENCE_SET_VEC_SCL(float, f, fmax);
-
-static void fail_f1(float v1, float v2, float actual, float expected, char *op_name) {
-    int dist = float_dist(actual, expected);
-    rsDebug("float operation did not match!", op_name);
-    rsDebug("v1", v1);
-    rsDebug("v2", v2);
-    rsDebug("Dalvik result", expected);
-    rsDebug("Renderscript result", actual);
-    rsDebug("ULP difference", dist);
-}
-
-static void fail_f2(float2 v1, float2 v2, float2 actual, float2 expected, char *op_name) {
-    int2 dist;
-    dist.x = float_dist(actual.x, expected.x);
-    dist.y = float_dist(actual.y, expected.y);
-    rsDebug("float2 operation did not match!", op_name);
-    rsDebug("v1.x", v1.x);
-    rsDebug("v1.y", v1.y);
-    rsDebug("v2.x", v2.x);
-    rsDebug("v2.y", v2.y);
-    rsDebug("Dalvik result .x", expected.x);
-    rsDebug("Dalvik result .y", expected.y);
-    rsDebug("Renderscript result .x", actual.x);
-    rsDebug("Renderscript result .y", actual.y);
-    rsDebug("ULP difference .x", dist.x);
-    rsDebug("ULP difference .y", dist.y);
-}
-
-static void fail_f3(float3 v1, float3 v2, float3 actual, float3 expected, char *op_name) {
-    int3 dist;
-    dist.x = float_dist(actual.x, expected.x);
-    dist.y = float_dist(actual.y, expected.y);
-    dist.z = float_dist(actual.z, expected.z);
-    rsDebug("float3 operation did not match!", op_name);
-    rsDebug("v1.x", v1.x);
-    rsDebug("v1.y", v1.y);
-    rsDebug("v1.z", v1.z);
-    rsDebug("v2.x", v2.x);
-    rsDebug("v2.y", v2.y);
-    rsDebug("v2.z", v2.z);
-    rsDebug("Dalvik result .x", expected.x);
-    rsDebug("Dalvik result .y", expected.y);
-    rsDebug("Dalvik result .z", expected.z);
-    rsDebug("Renderscript result .x", actual.x);
-    rsDebug("Renderscript result .y", actual.y);
-    rsDebug("Renderscript result .z", actual.z);
-    rsDebug("ULP difference .x", dist.x);
-    rsDebug("ULP difference .y", dist.y);
-    rsDebug("ULP difference .z", dist.z);
-}
-
-static void fail_f4(float4 v1, float4 v2, float4 actual, float4 expected, char *op_name) {
-    int4 dist;
-    dist.x = float_dist(actual.x, expected.x);
-    dist.y = float_dist(actual.y, expected.y);
-    dist.z = float_dist(actual.z, expected.z);
-    dist.w = float_dist(actual.w, expected.w);
-    rsDebug("float4 operation did not match!", op_name);
-    rsDebug("v1.x", v1.x);
-    rsDebug("v1.y", v1.y);
-    rsDebug("v1.z", v1.z);
-    rsDebug("v1.w", v1.w);
-    rsDebug("v2.x", v2.x);
-    rsDebug("v2.y", v2.y);
-    rsDebug("v2.z", v2.z);
-    rsDebug("v2.w", v2.w);
-    rsDebug("Dalvik result .x", expected.x);
-    rsDebug("Dalvik result .y", expected.y);
-    rsDebug("Dalvik result .z", expected.z);
-    rsDebug("Dalvik result .w", expected.w);
-    rsDebug("Renderscript result .x", actual.x);
-    rsDebug("Renderscript result .y", actual.y);
-    rsDebug("Renderscript result .z", actual.z);
-    rsDebug("Renderscript result .w", actual.w);
-    rsDebug("ULP difference .x", dist.x);
-    rsDebug("ULP difference .y", dist.y);
-    rsDebug("ULP difference .z", dist.z);
-    rsDebug("ULP difference .w", dist.w);
-}
-
-static bool f1_almost_equal(float a, float b) {
-    return float_almost_equal(a, b);
-}
-
-static bool f2_almost_equal(float2 a, float2 b) {
-    return float_almost_equal(a.x, b.x) && float_almost_equal(a.y, b.y);
-}
-
-
-static bool f3_almost_equal(float3 a, float3 b) {
-    return float_almost_equal(a.x, b.x) && float_almost_equal(a.y, b.y)
-            && float_almost_equal(a.z, b.z);
-}
-
-static bool f4_almost_equal(float4 a, float4 b) {
-    return float_almost_equal(a.x, b.x) && float_almost_equal(a.y, b.y)
-            && float_almost_equal(a.z, b.z) && float_almost_equal(a.w, b.w);
-}
-
-#define TEST_BASIC_FLOAT_OP(op, opName)                 \
-temp_f1 = x op y;                                       \
-if (! float_almost_equal(temp_f1, result_##opName)) {   \
-    fail_f1(x, y , temp_f1, result_##opName, #opName);  \
-    failed = true;                                      \
-}
-
-#define TEST_FN_FN(func, size)                                                  \
-temp_f##size = func(rand_f##size##_0, rand_f##size##_1);                        \
-if (! f##size##_almost_equal(temp_f##size , func##_rand_f##size##_f##size)) {   \
-    fail_f##size (x, y , temp_f##size, func##_rand_f##size##_f##size, #func);   \
-    failed = true;                                                              \
-}
-#define TEST_FN_F(func, size)                                               \
-temp_f##size = func(rand_f##size##_0, rand_f1_1);                           \
-if (! f##size##_almost_equal(temp_f##size , func##_rand_f##size##_f1)) {    \
-    fail_f##size (x, y , temp_f##size, func##_rand_f##size##_f1 , #func);   \
-    failed = true;                                                          \
-}
-
-#define TEST_FN_FN_ALL(func)    \
-TEST_FN_FN(func, 1)             \
-TEST_FN_FN(func, 2)             \
-TEST_FN_FN(func, 3)             \
-TEST_FN_FN(func, 4)
-#define TEST_FN_F_ALL(func) \
-TEST_FN_F(func, 2)          \
-TEST_FN_F(func, 3)          \
-TEST_FN_F(func, 4)
-
-#define TEST_VEC1_VEC1(func, type)                              \
-temp_##type##1 = func( rand_##type##1_0, rand_##type##1_1 );    \
-if (temp_##type##1 != func##_rand_##type##1_##type##1) {        \
-    rsDebug(#func " " #type "1 operation did not match!", 0);   \
-    rsDebug("v1", rand_##type##1_0);                            \
-    rsDebug("v2", rand_##type##1_1);                            \
-    rsDebug("Dalvik result", func##_rand_##type##1_##type##1);  \
-    rsDebug("Renderscript result", temp_##type##1);             \
-    failed = true;                                              \
-}
-#define TEST_VEC2_VEC2(func, type)                                      \
-temp_##type##2 = func( rand_##type##2_0, rand_##type##2_1 );            \
-if (temp_##type##2 .x != func##_rand_##type##2_##type##2 .x             \
-        || temp_##type##2 .y != func##_rand_##type##2_##type##2 .y) {   \
-    rsDebug(#func " " #type "2 operation did not match!", 0);           \
-    rsDebug("v1.x", rand_##type##2_0 .x);                               \
-    rsDebug("v1.y", rand_##type##2_0 .y);                               \
-    rsDebug("v2.x", rand_##type##2_1 .x);                               \
-    rsDebug("v2.y", rand_##type##2_1 .y);                               \
-    rsDebug("Dalvik result .x", func##_rand_##type##2_##type##2 .x);    \
-    rsDebug("Dalvik result .y", func##_rand_##type##2_##type##2 .y);    \
-    rsDebug("Renderscript result .x", temp_##type##2 .x);               \
-    rsDebug("Renderscript result .y", temp_##type##2 .y);               \
-    failed = true;                                                      \
-}
-#define TEST_VEC3_VEC3(func, type)                                      \
-temp_##type##3 = func( rand_##type##3_0, rand_##type##3_1 );            \
-if (temp_##type##3 .x != func##_rand_##type##3_##type##3 .x             \
-        || temp_##type##3 .y != func##_rand_##type##3_##type##3 .y      \
-        || temp_##type##3 .z != func##_rand_##type##3_##type##3 .z) {   \
-    rsDebug(#func " " #type "3 operation did not match!", 0);           \
-    rsDebug("v1.x", rand_##type##3_0 .x);                               \
-    rsDebug("v1.y", rand_##type##3_0 .y);                               \
-    rsDebug("v1.z", rand_##type##3_0 .z);                               \
-    rsDebug("v2.x", rand_##type##3_1 .x);                               \
-    rsDebug("v2.y", rand_##type##3_1 .y);                               \
-    rsDebug("v2.z", rand_##type##3_1 .z);                               \
-    rsDebug("Dalvik result .x", func##_rand_##type##3_##type##3 .x);    \
-    rsDebug("Dalvik result .y", func##_rand_##type##3_##type##3 .y);    \
-    rsDebug("Dalvik result .z", func##_rand_##type##3_##type##3 .z);    \
-    rsDebug("Renderscript result .x", temp_##type##3 .x);               \
-    rsDebug("Renderscript result .y", temp_##type##3 .y);               \
-    rsDebug("Renderscript result .z", temp_##type##3 .z);               \
-    failed = true;                                                      \
-}
-#define TEST_VEC4_VEC4(func, type)                                      \
-temp_##type##4 = func( rand_##type##4_0, rand_##type##4_1 );            \
-if (temp_##type##4 .x != func##_rand_##type##4_##type##4 .x             \
-        || temp_##type##4 .y != func##_rand_##type##4_##type##4 .y      \
-        || temp_##type##4 .z != func##_rand_##type##4_##type##4 .z      \
-        || temp_##type##4 .w != func##_rand_##type##4_##type##4 .w) {   \
-    rsDebug(#func " " #type "4 operation did not match!", 0);           \
-    rsDebug("v1.x", rand_##type##4_0 .x);                               \
-    rsDebug("v1.y", rand_##type##4_0 .y);                               \
-    rsDebug("v1.z", rand_##type##4_0 .z);                               \
-    rsDebug("v1.w", rand_##type##4_0 .w);                               \
-    rsDebug("v2.x", rand_##type##4_1 .x);                               \
-    rsDebug("v2.y", rand_##type##4_1 .y);                               \
-    rsDebug("v2.z", rand_##type##4_1 .z);                               \
-    rsDebug("v2.w", rand_##type##4_1 .w);                               \
-    rsDebug("Dalvik result .x", func##_rand_##type##4_##type##4 .x);    \
-    rsDebug("Dalvik result .y", func##_rand_##type##4_##type##4 .y);    \
-    rsDebug("Dalvik result .z", func##_rand_##type##4_##type##4 .z);    \
-    rsDebug("Dalvik result .w", func##_rand_##type##4_##type##4 .w);    \
-    rsDebug("Renderscript result .x", temp_##type##4 .x);               \
-    rsDebug("Renderscript result .y", temp_##type##4 .y);               \
-    rsDebug("Renderscript result .z", temp_##type##4 .z);               \
-    rsDebug("Renderscript result .w", temp_##type##4 .w);               \
-    failed = true;                                                      \
-}
-
-#define TEST_SC1_SC1(func)  TEST_VEC1_VEC1(func, sc)
-#define TEST_SC2_SC2(func)  TEST_VEC2_VEC2(func, sc)
-#define TEST_SC3_SC3(func)  TEST_VEC3_VEC3(func, sc)
-#define TEST_SC4_SC4(func)  TEST_VEC4_VEC4(func, sc)
-
-#define TEST_UC1_UC1(func)  TEST_VEC1_VEC1(func, uc)
-#define TEST_UC2_UC2(func)  TEST_VEC2_VEC2(func, uc)
-#define TEST_UC3_UC3(func)  TEST_VEC3_VEC3(func, uc)
-#define TEST_UC4_UC4(func)  TEST_VEC4_VEC4(func, uc)
-
-#define TEST_SS1_SS1(func)  TEST_VEC1_VEC1(func, ss)
-#define TEST_SS2_SS2(func)  TEST_VEC2_VEC2(func, ss)
-#define TEST_SS3_SS3(func)  TEST_VEC3_VEC3(func, ss)
-#define TEST_SS4_SS4(func)  TEST_VEC4_VEC4(func, ss)
-
-#define TEST_US1_US1(func)  TEST_VEC1_VEC1(func, us)
-#define TEST_US2_US2(func)  TEST_VEC2_VEC2(func, us)
-#define TEST_US3_US3(func)  TEST_VEC3_VEC3(func, us)
-#define TEST_US4_US4(func)  TEST_VEC4_VEC4(func, us)
-
-#define TEST_SI1_SI1(func)  TEST_VEC1_VEC1(func, si)
-#define TEST_SI2_SI2(func)  TEST_VEC2_VEC2(func, si)
-#define TEST_SI3_SI3(func)  TEST_VEC3_VEC3(func, si)
-#define TEST_SI4_SI4(func)  TEST_VEC4_VEC4(func, si)
-
-#define TEST_UI1_UI1(func)  TEST_VEC1_VEC1(func, ui)
-#define TEST_UI2_UI2(func)  TEST_VEC2_VEC2(func, ui)
-#define TEST_UI3_UI3(func)  TEST_VEC3_VEC3(func, ui)
-#define TEST_UI4_UI4(func)  TEST_VEC4_VEC4(func, ui)
-
-#define TEST_SL1_SL1(func)  TEST_VEC1_VEC1(func, sl)
-#define TEST_SL2_SL2(func)  TEST_VEC2_VEC2(func, sl)
-#define TEST_SL3_SL3(func)  TEST_VEC3_VEC3(func, sl)
-#define TEST_SL4_SL4(func)  TEST_VEC4_VEC4(func, sl)
-
-#define TEST_UL1_UL1(func)  TEST_VEC1_VEC1(func, ul)
-#define TEST_UL2_UL2(func)  TEST_VEC2_VEC2(func, ul)
-#define TEST_UL3_UL3(func)  TEST_VEC3_VEC3(func, ul)
-#define TEST_UL4_UL4(func)  TEST_VEC4_VEC4(func, ul)
-
-#define TEST_SC_SC_ALL(func)    \
-TEST_SC1_SC1(func)              \
-TEST_SC2_SC2(func)              \
-TEST_SC3_SC3(func)              \
-TEST_SC4_SC4(func)
-#define TEST_UC_UC_ALL(func)    \
-TEST_UC1_UC1(func)              \
-TEST_UC2_UC2(func)              \
-TEST_UC3_UC3(func)              \
-TEST_UC4_UC4(func)
-
-#define TEST_SS_SS_ALL(func)    \
-TEST_SS1_SS1(func)              \
-TEST_SS2_SS2(func)              \
-TEST_SS3_SS3(func)              \
-TEST_SS4_SS4(func)
-#define TEST_US_US_ALL(func)    \
-TEST_US1_US1(func)              \
-TEST_US2_US2(func)              \
-TEST_US3_US3(func)              \
-TEST_US4_US4(func)
-#define TEST_SI_SI_ALL(func)    \
-TEST_SI1_SI1(func)              \
-TEST_SI2_SI2(func)              \
-TEST_SI3_SI3(func)              \
-TEST_SI4_SI4(func)
-#define TEST_UI_UI_ALL(func)    \
-TEST_UI1_UI1(func)              \
-TEST_UI2_UI2(func)              \
-TEST_UI3_UI3(func)              \
-TEST_UI4_UI4(func)
-#define TEST_SL_SL_ALL(func)    \
-TEST_SL1_SL1(func)              \
-TEST_SL2_SL2(func)              \
-TEST_SL3_SL3(func)              \
-TEST_SL4_SL4(func)
-#define TEST_UL_UL_ALL(func)    \
-TEST_UL1_UL1(func)              \
-TEST_UL2_UL2(func)              \
-TEST_UL3_UL3(func)              \
-TEST_UL4_UL4(func)
-
-#define TEST_VEC_VEC_ALL(func)  \
-TEST_FN_FN_ALL(func)            \
-TEST_SC_SC_ALL(func)            \
-TEST_UC_UC_ALL(func)            \
-TEST_SS_SS_ALL(func)            \
-TEST_US_US_ALL(func)            \
-TEST_SI_SI_ALL(func)            \
-TEST_UI_UI_ALL(func)
-
-// TODO:  add long types to ALL macro
-#if 0
-TEST_SL_SL_ALL(func)            \
-TEST_UL_UL_ALL(func)
-#endif
-
-#define DECLARE_TEMP_SET(type, abbrev)  \
-volatile type    temp_##abbrev##1;               \
-volatile type##2 temp_##abbrev##2;               \
-volatile type##3 temp_##abbrev##3;               \
-volatile type##4 temp_##abbrev##4;
-
-#define DECLARE_ALL_TEMP_SETS() \
-DECLARE_TEMP_SET(float, f);     \
-DECLARE_TEMP_SET(char, sc);     \
-DECLARE_TEMP_SET(uchar, uc);    \
-DECLARE_TEMP_SET(short, ss);    \
-DECLARE_TEMP_SET(ushort, us);   \
-DECLARE_TEMP_SET(int, si);      \
-DECLARE_TEMP_SET(uint, ui);     \
-DECLARE_TEMP_SET(long, sl);     \
-DECLARE_TEMP_SET(ulong, ul);
-
-static bool test_math_agree() {
-    bool failed = false;
-
-    DECLARE_ALL_TEMP_SETS();
-
-    TEST_BASIC_FLOAT_OP(+, add);
-    TEST_BASIC_FLOAT_OP(-, sub);
-    TEST_BASIC_FLOAT_OP(*, mul);
-    TEST_BASIC_FLOAT_OP(/, div);
-
-    TEST_VEC_VEC_ALL(min);
-    TEST_VEC_VEC_ALL(max);
-    TEST_FN_FN_ALL(fmin);
-    TEST_FN_F_ALL(fmin);
-    TEST_FN_FN_ALL(fmax);
-    TEST_FN_F_ALL(fmax);
-
-    if (failed) {
-        rsDebug("test_math_agree FAILED", 0);
-    }
-    else {
-        rsDebug("test_math_agree PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_agree_test() {
-    bool failed = false;
-    failed |= test_math_agree();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/math_conformance.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/math_conformance.rs
deleted file mode 100644
index 2d62f34..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/math_conformance.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "shared.rsh"
-
-// Testing math conformance
-
-static bool test_rootn() {
-    bool failed = false;
-
-    // rootn(x, 0) -> NaN
-    _RS_ASSERT(isnan(rootn(1.0f, 0)));
-
-    // rootn(+/-0, n) -> +/-inf for odd n < 0
-    _RS_ASSERT(isposinf(rootn(0.f, -3)));
-    _RS_ASSERT(isneginf(rootn(-0.f, -3)));
-
-    // rootn(+/-0, n) -> +inf for even n < 0
-    _RS_ASSERT(isposinf(rootn(0.f, -8)));
-    _RS_ASSERT(isposinf(rootn(-0.f, -8)));
-
-    // rootn(+/-0, n) -> +/-0 for odd n > 0
-    _RS_ASSERT(isposzero(rootn(0.f, 3)));
-    _RS_ASSERT(isnegzero(rootn(-0.f, 3)));
-
-    // rootn(+/-0, n) -> +0 for even n > 0
-    _RS_ASSERT(isposzero(rootn(0.f, 8)));
-    _RS_ASSERT(isposzero(rootn(-0.f, 8)));
-
-    // rootn(x, n) -> NaN for x < 0 and even n
-    _RS_ASSERT(isnan(rootn(-10000.f, -4)));
-    _RS_ASSERT(isnan(rootn(-10000.f, 4)));
-
-    // rootn(x, n) -> value for x < 0 and odd n
-    _RS_ASSERT(!isnan(rootn(-10000.f, -3)));
-    _RS_ASSERT(!isnan(rootn(-10000.f, 3)));
-
-    if (failed) {
-        rsDebug("test_rootn FAILED", -1);
-    }
-    else {
-        rsDebug("test_rootn PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_conformance_test() {
-    bool failed = false;
-    failed |= test_rootn();
-
-    if (failed) {
-        rsDebug("math_conformance_test FAILED", -1);
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsDebug("math_conformance_test PASSED", 0);
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
deleted file mode 100644
index 1354897..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_mesh mesh;
-rs_allocation vertexAlloc0;
-rs_allocation vertexAlloc1;
-
-rs_allocation indexAlloc0;
-rs_allocation indexAlloc2;
-
-static bool test_mesh_getters() {
-    bool failed = false;
-
-    _RS_ASSERT(rsgMeshGetVertexAllocationCount(mesh) == 2);
-    _RS_ASSERT(rsgMeshGetPrimitiveCount(mesh) == 3);
-
-    rs_allocation meshV0 = rsgMeshGetVertexAllocation(mesh, 0);
-    rs_allocation meshV1 = rsgMeshGetVertexAllocation(mesh, 1);
-    rs_allocation meshV2 = rsgMeshGetVertexAllocation(mesh, 2);
-    _RS_ASSERT(meshV0.p == vertexAlloc0.p);
-    _RS_ASSERT(meshV1.p == vertexAlloc1.p);
-    _RS_ASSERT(!rsIsObject(meshV2));
-
-    rs_allocation meshI0 = rsgMeshGetIndexAllocation(mesh, 0);
-    rs_allocation meshI1 = rsgMeshGetIndexAllocation(mesh, 1);
-    rs_allocation meshI2 = rsgMeshGetIndexAllocation(mesh, 2);
-    rs_allocation meshI3 = rsgMeshGetIndexAllocation(mesh, 3);
-    _RS_ASSERT(meshI0.p == indexAlloc0.p);
-    _RS_ASSERT(!rsIsObject(meshI1));
-    _RS_ASSERT(meshI2.p == indexAlloc2.p);
-    _RS_ASSERT(!rsIsObject(meshI3));
-
-    rs_primitive p0 = rsgMeshGetPrimitive(mesh, 0);
-    rs_primitive p1 = rsgMeshGetPrimitive(mesh, 1);
-    rs_primitive p2 = rsgMeshGetPrimitive(mesh, 2);
-    rs_primitive p3 = rsgMeshGetPrimitive(mesh, 3);
-
-    _RS_ASSERT(p0 == RS_PRIMITIVE_POINT);
-    _RS_ASSERT(p1 == RS_PRIMITIVE_LINE);
-    _RS_ASSERT(p2 == RS_PRIMITIVE_TRIANGLE);
-    _RS_ASSERT(p3 == RS_PRIMITIVE_INVALID);
-
-    if (failed) {
-        rsDebug("test_mesh_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_mesh_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void mesh_test() {
-    bool failed = false;
-    failed |= test_mesh_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/min.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/min.rs
deleted file mode 100644
index 4b92763..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/min.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "shared.rsh"
-#pragma rs_fp_relaxed
-
-volatile uchar2 res_uc_2 = 1;
-volatile uchar2 src1_uc_2 = 1;
-volatile uchar2 src2_uc_2 = 1;
-
-void min_test() {
-    bool failed = false;
-
-    res_uc_2 = min(src1_uc_2, src2_uc_2);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
deleted file mode 100644
index 2c807bd..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/noroot.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "shared.rsh"
-
-rs_allocation aRaw;
-int dimX;
-int dimY;
-static bool failed = false;
-
-void foo(const int *in, int *out, uint32_t x, uint32_t y) {
-    *out = 99 + x + y * dimX;
-}
-
-static bool test_foo_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            int v = rsGetElementAt_int(aRaw, i, j);
-            _RS_ASSERT(v == (99 + i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_foo_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_foo_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void verify_foo() {
-    failed |= test_foo_output();
-}
-
-void noroot_test() {
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/primitives.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/primitives.rs
deleted file mode 100644
index ce451da..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/primitives.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool test_primitive_types(uint32_t index) {
-    bool failed = false;
-    start();
-
-    _RS_ASSERT(floatTest == 2.99f);
-    _RS_ASSERT(doubleTest == 3.05);
-    _RS_ASSERT(charTest == -16);
-    _RS_ASSERT(shortTest == -32);
-    _RS_ASSERT(intTest == -64);
-    _RS_ASSERT(longTest == 17179869185l);
-    _RS_ASSERT(longlongTest == 68719476735l);
-
-    _RS_ASSERT(ucharTest == 8);
-    _RS_ASSERT(ushortTest == 16);
-    _RS_ASSERT(uintTest == 32);
-    _RS_ASSERT(ulongTest == 4611686018427387903L);
-    _RS_ASSERT(int64_tTest == -17179869184l);
-    _RS_ASSERT(uint64_tTest == 117179869185l);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_primitives FAILED", time);
-    }
-    else {
-        rsDebug("test_primitives PASSED", time);
-    }
-
-    return failed;
-}
-
-void primitives_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_primitive_types(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
deleted file mode 100644
index 3d6b502..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_program_raster pointSpriteEnabled;
-rs_program_raster cullMode;
-
-static bool test_program_raster_getters() {
-    bool failed = false;
-
-    _RS_ASSERT(rsgProgramRasterIsPointSpriteEnabled(pointSpriteEnabled) == true);
-    _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
-
-    _RS_ASSERT(rsgProgramRasterIsPointSpriteEnabled(cullMode) == false);
-    _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
-
-    if (failed) {
-        rsDebug("test_program_raster_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_program_raster_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void program_raster_test() {
-    bool failed = false;
-    failed |= test_program_raster_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
deleted file mode 100644
index 2ae5636..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_program_store ditherEnable;
-rs_program_store colorRWriteEnable;
-rs_program_store colorGWriteEnable;
-rs_program_store colorBWriteEnable;
-rs_program_store colorAWriteEnable;
-rs_program_store blendSrc;
-rs_program_store blendDst;
-rs_program_store depthWriteEnable;
-rs_program_store depthFunc;
-
-static bool test_program_store_getters() {
-    bool failed = false;
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(depthFunc) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(depthWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(depthWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorRWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorRWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorGWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorGWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorBWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorBWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorAWriteEnable) == true);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorAWriteEnable) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( ditherEnable) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(ditherEnable) == true);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(blendSrc) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
-
-    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
-    _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreIsDitherEnabled(blendDst) == false);
-    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
-    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
-
-    if (failed) {
-        rsDebug("test_program_store_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_program_store_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void program_store_test() {
-    bool failed = false;
-    failed |= test_program_store_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/refcount.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/refcount.rs
deleted file mode 100644
index 4ea70e2..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/refcount.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "shared.rsh"
-
-// Testing reference counting of RS object types
-
-rs_allocation globalA;
-static rs_allocation staticGlobalA;
-
-void refcount_test() {
-    staticGlobalA = globalA;
-    rsClearObject(&globalA);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rsdebug.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rsdebug.rs
deleted file mode 100644
index 68ac168..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rsdebug.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-float2 float2Test = {2.99f, 12.99f};
-float3 float3Test = {3.99f, 13.99f, 23.99f};
-float4 float4Test = {4.99f, 14.99f, 24.99f, 34.99f};
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    // For this reason, none of the outputs are actually checked.
-
-    rsDebug("floatTest", floatTest);
-    rsDebug("float2Test", float2Test);
-    rsDebug("float3Test", float3Test);
-    rsDebug("float4Test", float4Test);
-    rsDebug("doubleTest", doubleTest);
-    rsDebug("charTest", charTest);
-    rsDebug("shortTest", shortTest);
-    rsDebug("intTest", intTest);
-    rsDebug("longTest", longTest);
-    rsDebug("longlongTest", longlongTest);
-
-    rsDebug("ucharTest", ucharTest);
-    rsDebug("ushortTest", ushortTest);
-    rsDebug("uintTest", uintTest);
-    rsDebug("ulongTest", ulongTest);
-    rsDebug("int64_tTest", int64_tTest);
-    rsDebug("uint64_tTest", uint64_tTest);
-
-    return failed;
-}
-
-void test_rsdebug(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rsdebug_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rsdebug_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
deleted file mode 100644
index d8663fb..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (C) 2009 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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test)
-
-#include "rs_graphics.rsh"
-
-float gDY;
-
-rs_font gFont;
-
-typedef struct ListAllocs_s {
-    rs_allocation text;
-    int result;
-} ListAllocs;
-
-ListAllocs *gList;
-
-void init() {
-    gDY = 0.0f;
-}
-
-int textPos = 0;
-
-int root(void) {
-
-    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-    rsgClearDepth(1.0f);
-
-    textPos -= (int)gDY*2;
-    gDY *= 0.95;
-
-    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-    rsgBindFont(gFont);
-
-    rs_allocation listAlloc;
-    listAlloc = rsGetAllocation(gList);
-    int allocSize = rsAllocationGetDimX(listAlloc);
-
-    int width = rsgGetWidth();
-    int height = rsgGetHeight();
-
-    int itemHeight = 80;
-    int totalItemHeight = itemHeight * allocSize;
-
-    /* Prevent scrolling above the top of the list */
-    int firstItem = height - totalItemHeight;
-    if (firstItem < 0) {
-        firstItem = 0;
-    }
-
-    /* Prevent scrolling past the last line of the list */
-    int lastItem = -1 * (totalItemHeight - height);
-    if (lastItem > 0) {
-        lastItem = 0;
-    }
-
-    if (textPos > firstItem) {
-        textPos = firstItem;
-    }
-    else if (textPos < lastItem) {
-        textPos = lastItem;
-    }
-
-    int currentYPos = itemHeight + textPos;
-
-    for(int i = 0; i < allocSize; i ++) {
-        if(currentYPos - itemHeight > height) {
-            break;
-        }
-
-        if(currentYPos > 0) {
-            switch(gList[i].result) {
-                case 1: /* Passed */
-                    rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f);
-                    break;
-                case -1: /* Failed */
-                    rsgFontColor(0.9f, 0.5f, 0.5f, 1.0f);
-                    break;
-                case 0: /* Still Testing */
-                    rsgFontColor(0.9f, 0.9f, 0.5f, 1.0f);
-                    break;
-                default: /* Unknown */
-                    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-                    break;
-            }
-            rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
-            rsgDrawText(gList[i].text, 30, currentYPos - 32);
-        }
-        currentYPos += itemHeight;
-    }
-
-    return 10;
-}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs
deleted file mode 100644
index 7be955d..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "shared.rsh"
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_time_t curTime = rsTime(0);
-    rs_tm tm;
-    rsDebug("curTime", curTime);
-
-    rsLocaltime(&tm, &curTime);
-
-    rsDebug("tm.tm_sec", tm.tm_sec);
-    rsDebug("tm.tm_min", tm.tm_min);
-    rsDebug("tm.tm_hour", tm.tm_hour);
-    rsDebug("tm.tm_mday", tm.tm_mday);
-    rsDebug("tm.tm_mon", tm.tm_mon);
-    rsDebug("tm.tm_year", tm.tm_year);
-    rsDebug("tm.tm_wday", tm.tm_wday);
-    rsDebug("tm.tm_yday", tm.tm_yday);
-    rsDebug("tm.tm_isdst", tm.tm_isdst);
-
-    // Test a specific time (since we set America/Los_Angeles localtime)
-    curTime = 1294438893;
-    rsLocaltime(&tm, &curTime);
-
-    _RS_ASSERT(tm.tm_sec == 33);
-    _RS_ASSERT(tm.tm_min == 21);
-    _RS_ASSERT(tm.tm_hour == 14);
-    _RS_ASSERT(tm.tm_mday == 7);
-    _RS_ASSERT(tm.tm_mon == 0);
-    _RS_ASSERT(tm.tm_year == 111);
-    _RS_ASSERT(tm.tm_wday == 5);
-    _RS_ASSERT(tm.tm_yday == 6);
-    _RS_ASSERT(tm.tm_isdst == 0);
-
-    return failed;
-}
-
-void test_rstime(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstime_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstime_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
deleted file mode 100644
index 22d9c13..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_element elementTest;
-rs_type typeTest;
-rs_allocation allocationTest;
-rs_sampler samplerTest;
-rs_script scriptTest;
-rs_mesh meshTest;
-rs_program_fragment program_fragmentTest;
-rs_program_vertex program_vertexTest;
-rs_program_raster program_rasterTest;
-rs_program_store program_storeTest;
-rs_font fontTest;
-
-rs_matrix4x4 matrix4x4Test;
-rs_matrix3x3 matrix3x3Test;
-rs_matrix2x2 matrix2x2Test;
-
-struct my_struct {
-    int i;
-    rs_font fontTestStruct;
-};
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_matrix4x4 matrix4x4TestLocal;
-    rs_matrix3x3 matrix3x3TestLocal;
-    rs_matrix2x2 matrix2x2TestLocal;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    rs_element elementTestLocal;
-    rs_type typeTestLocal;
-    rs_allocation allocationTestLocal;
-    rs_sampler samplerTestLocal;
-    rs_script scriptTestLocal;
-    rs_mesh meshTestLocal;
-    rs_program_fragment program_fragmentTestLocal;
-    rs_program_vertex program_vertexTestLocal;
-    rs_program_raster program_rasterTestLocal;
-    rs_program_store program_storeTestLocal;
-    rs_font fontTestLocal;
-
-    rs_font fontTestLocalArray[4];
-
-    rs_font fontTestLocalPreInit = fontTest;
-
-    struct my_struct structTest;
-
-    fontTestLocal = fontTest;
-    //allocationTestLocal = allocationTest;
-
-    fontTest = fontTestLocal;
-    //allocationTest = allocationTestLocal;
-
-    /*for (int i = 0; i < 4; i++) {
-        fontTestLocalArray[i] = fontTestLocal;
-    }*/
-
-    /*fontTest = fontTestLocalArray[3];*/
-
-    return failed;
-}
-
-void test_rstypes(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstypes_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstypes_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
deleted file mode 100644
index ff1c0a7..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-rs_sampler minification;
-rs_sampler magnification;
-rs_sampler wrapS;
-rs_sampler wrapT;
-rs_sampler anisotropy;
-
-static bool test_sampler_getters() {
-    bool failed = false;
-
-    _RS_ASSERT(rsSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
-    _RS_ASSERT(rsSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(minification) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
-    _RS_ASSERT(rsSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(magnification) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
-    _RS_ASSERT(rsSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(wrapS) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(wrapT) == 1.0f);
-
-    _RS_ASSERT(rsSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
-    _RS_ASSERT(rsSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
-    _RS_ASSERT(rsSamplerGetAnisotropy(anisotropy) == 8.0f);
-
-    if (failed) {
-        rsDebug("test_sampler_getters FAILED", 0);
-    }
-    else {
-        rsDebug("test_sampler_getters PASSED", 0);
-    }
-
-    return failed;
-}
-
-void sampler_test() {
-    bool failed = false;
-    failed |= test_sampler_getters();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/shared.rsh b/tests/RenderScriptTests/tests/src/com/android/rs/test/shared.rsh
deleted file mode 100644
index 3adc999..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/shared.rsh
+++ /dev/null
@@ -1,114 +0,0 @@
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test)
-
-typedef struct TestResult_s {
-    rs_allocation name;
-    bool pass;
-    float score;
-    int64_t time;
-} TestResult;
-//TestResult *g_results;
-
-static int64_t g_time;
-
-static void start(void) {
-    g_time = rsUptimeMillis();
-}
-
-static float end(uint32_t idx) {
-    int64_t t = rsUptimeMillis() - g_time;
-    //g_results[idx].time = t;
-    //rsDebug("test time", (int)t);
-    return ((float)t) / 1000.f;
-}
-
-#define _RS_ASSERT(b) \
-do { \
-    if (!(b)) { \
-        failed = true; \
-        rsDebug(#b " FAILED", 0); \
-    } \
-\
-} while (0)
-
-static const int iposinf = 0x7f800000;
-static const int ineginf = 0xff800000;
-
-static const float posinf() {
-    float f = *((float*)&iposinf);
-    return f;
-}
-
-static const float neginf() {
-    float f = *((float*)&ineginf);
-    return f;
-}
-
-static bool isposinf(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == iposinf);
-}
-
-static bool isneginf(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == ineginf);
-}
-
-static bool isnan(float f) {
-    int i = *((int*)(void*)&f);
-    return (((i & 0x7f800000) == 0x7f800000) && (i & 0x007fffff));
-}
-
-static bool isposzero(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == 0x00000000);
-}
-
-static bool isnegzero(float f) {
-    int i = *((int*)(void*)&f);
-    return (i == 0x80000000);
-}
-
-static bool iszero(float f) {
-    return isposzero(f) || isnegzero(f);
-}
-
-/* Absolute epsilon used for floats.  Value is similar to float.h. */
-#ifndef FLT_EPSILON
-#define FLT_EPSILON 1.19e7f
-#endif
-/* Max ULPs while still being considered "equal".  Only used when this number
-   of ULPs is of a greater size than FLT_EPSILON. */
-#define FLT_MAX_ULP 1
-
-/* Calculate the difference in ULPs between the two values.  (Return zero on
-   perfect equality.) */
-static int float_dist(float f1, float f2) {
-    return *((int *)(&f1)) - *((int *)(&f2));
-}
-
-/* Check if two floats are essentially equal.  Will fail with some values
-   due to design.  (Validate using FLT_EPSILON or similar if necessary.) */
-static bool float_almost_equal(float f1, float f2) {
-    int *i1 = (int*)(&f1);
-    int *i2 = (int*)(&f2);
-
-    // Check for sign equality
-    if ( ((*i1 >> 31) == 0) != ((*i2 >> 31) == 0) ) {
-        // Handle signed zeroes
-        if (f1 == f2)
-            return true;
-        return false;
-    }
-
-    // Check with ULP distance
-    if (float_dist(f1, f2) > FLT_MAX_ULP)
-        return false;
-    return true;
-}
-
-/* These constants must match those in UnitTest.java */
-static const int RS_MSG_TEST_PASSED = 100;
-static const int RS_MSG_TEST_FAILED = 101;
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
deleted file mode 100644
index 1cd728e..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "shared.rsh"
-
-typedef struct Point2 {
-   int x;
-   int y;
-} Point_2;
-Point_2 *point2;
-
-static bool test_Point_2(int expected) {
-    bool failed = false;
-
-    rsDebug("Point: ", point2[0].x, point2[0].y);
-    _RS_ASSERT(point2[0].x == expected);
-    _RS_ASSERT(point2[0].y == expected);
-
-    if (failed) {
-        rsDebug("test_Point_2 FAILED", 0);
-    }
-    else {
-        rsDebug("test_Point_2 PASSED", 0);
-    }
-
-    return failed;
-}
-
-void struct_test(int expected) {
-    bool failed = false;
-    failed |= test_Point_2(expected);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/test_root.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/test_root.rs
deleted file mode 100644
index 6dc83ba..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/test_root.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-
-typedef struct TestResult {
-    rs_allocation name;
-    bool pass;
-    float score;
-} TestResult_t;
-TestResult_t *results;
-
-int root() {
-
-    return 0;
-}
-
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/unsigned.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/unsigned.rs
deleted file mode 100644
index 2c056f4..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/unsigned.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "shared.rsh"
-
-// Testing unsigned types for Bug 6764163
-unsigned int ui = 37;
-unsigned char uc = 5;
-
-static bool test_unsigned() {
-    bool failed = false;
-
-    rsDebug("ui", ui);
-    rsDebug("uc", uc);
-    _RS_ASSERT(ui == 0x7fffffff);
-    _RS_ASSERT(uc == 129);
-
-    if (failed) {
-        rsDebug("test_unsigned FAILED", -1);
-    }
-    else {
-        rsDebug("test_unsigned PASSED", 0);
-    }
-
-    return failed;
-}
-
-void unsigned_test() {
-    bool failed = false;
-    failed |= test_unsigned();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/vector.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/vector.rs
deleted file mode 100644
index 0430a2f..0000000
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/vector.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "shared.rsh"
-
-// Testing vector types
-float2 f2 = { 1.0f, 2.0f };
-float3 f3 = { 1.0f, 2.0f, 3.0f };
-float4 f4 = { 1.0f, 2.0f, 3.0f, 4.0f };
-
-double2 d2 = { 1.0, 2.0 };
-double3 d3 = { 1.0, 2.0, 3.0 };
-double4 d4 = { 1.0, 2.0, 3.0, 4.0 };
-
-char2 i8_2 = { 1, 2 };
-char3 i8_3 = { 1, 2, 3 };
-char4 i8_4 = { 1, 2, 3, 4 };
-
-uchar2 u8_2 = { 1, 2 };
-uchar3 u8_3 = { 1, 2, 3 };
-uchar4 u8_4 = { 1, 2, 3, 4 };
-
-short2 i16_2 = { 1, 2 };
-short3 i16_3 = { 1, 2, 3 };
-short4 i16_4 = { 1, 2, 3, 4 };
-
-ushort2 u16_2 = { 1, 2 };
-ushort3 u16_3 = { 1, 2, 3 };
-ushort4 u16_4 = { 1, 2, 3, 4 };
-
-int2 i32_2 = { 1, 2 };
-int3 i32_3 = { 1, 2, 3 };
-int4 i32_4 = { 1, 2, 3, 4 };
-
-uint2 u32_2 = { 1, 2 };
-uint3 u32_3 = { 1, 2, 3 };
-uint4 u32_4 = { 1, 2, 3, 4 };
-
-long2 i64_2 = { 1, 2 };
-long3 i64_3 = { 1, 2, 3 };
-long4 i64_4 = { 1, 2, 3, 4 };
-
-ulong2 u64_2 = { 1, 2 };
-ulong3 u64_3 = { 1, 2, 3 };
-ulong4 u64_4 = { 1, 2, 3, 4 };
-
-static bool test_vector_types() {
-    bool failed = false;
-
-    rsDebug("Testing F32", 0);
-    _RS_ASSERT(f2.x == 2.99f);
-    _RS_ASSERT(f2.y == 3.99f);
-
-    _RS_ASSERT(f3.x == 2.99f);
-    _RS_ASSERT(f3.y == 3.99f);
-    _RS_ASSERT(f3.z == 4.99f);
-
-    _RS_ASSERT(f4.x == 2.99f);
-    _RS_ASSERT(f4.y == 3.99f);
-    _RS_ASSERT(f4.z == 4.99f);
-    _RS_ASSERT(f4.w == 5.99f);
-
-    rsDebug("Testing F64", 0);
-    _RS_ASSERT(d2.x == 2.99);
-    _RS_ASSERT(d2.y == 3.99);
-
-    _RS_ASSERT(d3.x == 2.99);
-    _RS_ASSERT(d3.y == 3.99);
-    _RS_ASSERT(d3.z == 4.99);
-
-    _RS_ASSERT(d4.x == 2.99);
-    _RS_ASSERT(d4.y == 3.99);
-    _RS_ASSERT(d4.z == 4.99);
-    _RS_ASSERT(d4.w == 5.99);
-
-    rsDebug("Testing I8", 0);
-    _RS_ASSERT(i8_2.x == 2);
-    _RS_ASSERT(i8_2.y == 3);
-
-    _RS_ASSERT(i8_3.x == 2);
-    _RS_ASSERT(i8_3.y == 3);
-    _RS_ASSERT(i8_3.z == 4);
-
-    _RS_ASSERT(i8_4.x == 2);
-    _RS_ASSERT(i8_4.y == 3);
-    _RS_ASSERT(i8_4.z == 4);
-    _RS_ASSERT(i8_4.w == 5);
-
-    rsDebug("Testing U8", 0);
-    _RS_ASSERT(u8_2.x == 2);
-    _RS_ASSERT(u8_2.y == 3);
-
-    _RS_ASSERT(u8_3.x == 2);
-    _RS_ASSERT(u8_3.y == 3);
-    _RS_ASSERT(u8_3.z == 4);
-
-    _RS_ASSERT(u8_4.x == 2);
-    _RS_ASSERT(u8_4.y == 3);
-    _RS_ASSERT(u8_4.z == 4);
-    _RS_ASSERT(u8_4.w == 5);
-
-    rsDebug("Testing I16", 0);
-    _RS_ASSERT(i16_2.x == 2);
-    _RS_ASSERT(i16_2.y == 3);
-
-    _RS_ASSERT(i16_3.x == 2);
-    _RS_ASSERT(i16_3.y == 3);
-    _RS_ASSERT(i16_3.z == 4);
-
-    _RS_ASSERT(i16_4.x == 2);
-    _RS_ASSERT(i16_4.y == 3);
-    _RS_ASSERT(i16_4.z == 4);
-    _RS_ASSERT(i16_4.w == 5);
-
-    rsDebug("Testing U16", 0);
-    _RS_ASSERT(u16_2.x == 2);
-    _RS_ASSERT(u16_2.y == 3);
-
-    _RS_ASSERT(u16_3.x == 2);
-    _RS_ASSERT(u16_3.y == 3);
-    _RS_ASSERT(u16_3.z == 4);
-
-    _RS_ASSERT(u16_4.x == 2);
-    _RS_ASSERT(u16_4.y == 3);
-    _RS_ASSERT(u16_4.z == 4);
-    _RS_ASSERT(u16_4.w == 5);
-
-    rsDebug("Testing I32", 0);
-    _RS_ASSERT(i32_2.x == 2);
-    _RS_ASSERT(i32_2.y == 3);
-
-    _RS_ASSERT(i32_3.x == 2);
-    _RS_ASSERT(i32_3.y == 3);
-    _RS_ASSERT(i32_3.z == 4);
-
-    _RS_ASSERT(i32_4.x == 2);
-    _RS_ASSERT(i32_4.y == 3);
-    _RS_ASSERT(i32_4.z == 4);
-    _RS_ASSERT(i32_4.w == 5);
-
-    rsDebug("Testing U32", 0);
-    _RS_ASSERT(u32_2.x == 2);
-    _RS_ASSERT(u32_2.y == 3);
-
-    _RS_ASSERT(u32_3.x == 2);
-    _RS_ASSERT(u32_3.y == 3);
-    _RS_ASSERT(u32_3.z == 4);
-
-    _RS_ASSERT(u32_4.x == 2);
-    _RS_ASSERT(u32_4.y == 3);
-    _RS_ASSERT(u32_4.z == 4);
-    _RS_ASSERT(u32_4.w == 5);
-
-    rsDebug("Testing I64", 0);
-    _RS_ASSERT(i64_2.x == 2);
-    _RS_ASSERT(i64_2.y == 3);
-
-    _RS_ASSERT(i64_3.x == 2);
-    _RS_ASSERT(i64_3.y == 3);
-    _RS_ASSERT(i64_3.z == 4);
-
-    _RS_ASSERT(i64_4.x == 2);
-    _RS_ASSERT(i64_4.y == 3);
-    _RS_ASSERT(i64_4.z == 4);
-    _RS_ASSERT(i64_4.w == 5);
-
-    rsDebug("Testing U64", 0);
-    _RS_ASSERT(u64_2.x == 2);
-    _RS_ASSERT(u64_2.y == 3);
-
-    _RS_ASSERT(u64_3.x == 2);
-    _RS_ASSERT(u64_3.y == 3);
-    _RS_ASSERT(u64_3.z == 4);
-
-    _RS_ASSERT(u64_4.x == 2);
-    _RS_ASSERT(u64_4.y == 3);
-    _RS_ASSERT(u64_4.z == 4);
-    _RS_ASSERT(u64_4.w == 5);
-
-    if (failed) {
-        rsDebug("test_vector FAILED", 0);
-    }
-    else {
-        rsDebug("test_vector PASSED", 0);
-    }
-
-    return failed;
-}
-
-void vector_test() {
-    bool failed = false;
-    failed |= test_vector_types();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v11/Android.mk b/tests/RenderScriptTests/tests_v11/Android.mk
deleted file mode 100644
index 52d326b..0000000
--- a/tests/RenderScriptTests/tests_v11/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-
-ifneq ($(TARGET_SIMULATOR),true)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RSTest_v11
-LOCAL_SDK_VERSION := 11
-
-include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/RenderScriptTests/tests_v11/AndroidManifest.xml b/tests/RenderScriptTests/tests_v11/AndroidManifest.xml
deleted file mode 100644
index f4aeda2..0000000
--- a/tests/RenderScriptTests/tests_v11/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.test_v11">
-    <uses-sdk android:minSdkVersion="11" />
-    <application 
-        android:label="_RS_Test_v11"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="RSTest_v11"
-                  android:screenOrientation="portrait">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/tests_v11/res/drawable/test_pattern.png b/tests/RenderScriptTests/tests_v11/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/tests_v11/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTestCore.java
deleted file mode 100644
index 888cfe4..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTestCore.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.ListIterator;
-import java.util.Timer;
-import java.util.TimerTask;
-
-
-public class RSTestCore {
-    int mWidth;
-    int mHeight;
-    Context mCtx;
-
-    public RSTestCore(Context ctx) {
-        mCtx = ctx;
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    private Font mFont;
-    ScriptField_ListAllocs_s mListAllocs;
-    int mLastX;
-    int mLastY;
-    private ScriptC_rslist mScript;
-
-    private ArrayList<UnitTest> unitTests;
-    private ListIterator<UnitTest> test_iter;
-    private UnitTest activeTest;
-    private boolean stopTesting;
-
-    /* Periodic timer for ensuring future tests get scheduled */
-    private Timer mTimer;
-    public static final int RS_TIMER_PERIOD = 100;
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-        stopTesting = false;
-
-        mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist);
-
-        unitTests = new ArrayList<UnitTest>();
-
-        unitTests.add(new UT_primitives(this, mRes, mCtx));
-        unitTests.add(new UT_rsdebug(this, mRes, mCtx));
-        unitTests.add(new UT_rstime(this, mRes, mCtx));
-        unitTests.add(new UT_rstypes(this, mRes, mCtx));
-        unitTests.add(new UT_math(this, mRes, mCtx));
-        unitTests.add(new UT_fp_mad(this, mRes, mCtx));
-        /*
-        unitTests.add(new UnitTest(null, "<Pass>", 1));
-        unitTests.add(new UnitTest());
-        unitTests.add(new UnitTest(null, "<Fail>", -1));
-
-        for (int i = 0; i < 20; i++) {
-            unitTests.add(new UnitTest(null, "<Pass>", 1));
-        }
-        */
-
-        UnitTest [] uta = new UnitTest[unitTests.size()];
-        uta = unitTests.toArray(uta);
-
-        mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length);
-        for (int i = 0; i < uta.length; i++) {
-            ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
-            listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
-            listElem.result = uta[i].result;
-            mListAllocs.set(listElem, i, false);
-            uta[i].setItem(listElem);
-        }
-
-        mListAllocs.copyAll();
-
-        mScript.bind_gList(mListAllocs);
-
-        mFont = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8);
-        mScript.set_gFont(mFont);
-
-        mRS.bindRootScript(mScript);
-
-        test_iter = unitTests.listIterator();
-        refreshTestResults(); /* Kick off the first test */
-
-        TimerTask pTask = new TimerTask() {
-            public void run() {
-                refreshTestResults();
-            }
-        };
-
-        mTimer = new Timer();
-        mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD);
-    }
-
-    public void checkAndRunNextTest() {
-        if (activeTest != null) {
-            if (!activeTest.isAlive()) {
-                /* Properly clean up on our last test */
-                try {
-                    activeTest.join();
-                }
-                catch (InterruptedException e) {
-                }
-                activeTest = null;
-            }
-        }
-
-        if (!stopTesting && activeTest == null) {
-            if (test_iter.hasNext()) {
-                activeTest = test_iter.next();
-                activeTest.start();
-                /* This routine will only get called once when a new test
-                 * should start running. The message handler in UnitTest.java
-                 * ensures this. */
-            }
-            else {
-                if (mTimer != null) {
-                    mTimer.cancel();
-                    mTimer.purge();
-                    mTimer = null;
-                }
-            }
-        }
-    }
-
-    public void refreshTestResults() {
-        checkAndRunNextTest();
-
-        if (mListAllocs != null && mScript != null && mRS != null) {
-            mListAllocs.copyAll();
-
-            mScript.bind_gList(mListAllocs);
-            mRS.bindRootScript(mScript);
-        }
-    }
-
-    public void cleanup() {
-        stopTesting = true;
-        UnitTest t = activeTest;
-
-        /* Stop periodic refresh of testing */
-        if (mTimer != null) {
-            mTimer.cancel();
-            mTimer.purge();
-            mTimer = null;
-        }
-
-        /* Wait to exit until we finish the current test */
-        if (t != null) {
-            try {
-                t.join();
-            }
-            catch (InterruptedException e) {
-            }
-            t = null;
-        }
-
-    }
-
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-    }
-
-    public void onActionDown(int x, int y) {
-        mScript.set_gDY(0.0f);
-        mLastX = x;
-        mLastY = y;
-        refreshTestResults();
-    }
-
-    public void onActionMove(int x, int y) {
-        int dx = mLastX - x;
-        int dy = mLastY - y;
-
-        if (Math.abs(dy) <= 2) {
-            dy = 0;
-        }
-
-        mScript.set_gDY(dy);
-
-        mLastX = x;
-        mLastY = y;
-        refreshTestResults();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTestView.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTestView.java
deleted file mode 100644
index b5bebe9..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTestView.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test_v11;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class RSTestView extends RSSurfaceView {
-
-    private Context mCtx;
-
-    public RSTestView(Context context) {
-        super(context);
-        mCtx = context;
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private RSTestCore mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new RSTestCore(mCtx);
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if(mRS != null) {
-            mRender.cleanup();
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event)
-    {
-        return super.onKeyDown(keyCode, event);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        boolean ret = false;
-        int act = ev.getAction();
-        if (act == ev.ACTION_DOWN) {
-            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-        else if (act == ev.ACTION_MOVE) {
-            mRender.onActionMove((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-
-        return ret;
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTest_v11.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTest_v11.java
deleted file mode 100644
index 1dedfce..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/RSTest_v11.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test_v11;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Config;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import java.lang.Runtime;
-
-public class RSTest_v11 extends Activity {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
-
-    private RSTestView mView;
-
-    // get the current looper (from your Activity UI thread for instance
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RSTestView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onPause();
-        mView.pause();
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_fp_mad.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_fp_mad.java
deleted file mode 100644
index 5d72aa6..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_fp_mad.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_fp_mad extends UnitTest {
-    private Resources mRes;
-
-    protected UT_fp_mad(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Fp_Mad", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_fp_mad s = new ScriptC_fp_mad(pRS, mRes, R.raw.fp_mad);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_fp_mad_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_math.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_math.java
deleted file mode 100644
index 7e356f8..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_math.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_math extends UnitTest {
-    private Resources mRes;
-
-    protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math s = new ScriptC_math(pRS, mRes, R.raw.math);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_math_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_primitives.java
deleted file mode 100644
index dc3efbc..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_primitives.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_primitives extends UnitTest {
-    private Resources mRes;
-
-    protected UT_primitives(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Primitives", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_primitives s) {
-        float pF = s.get_floatTest();
-        if (pF != 1.99f) {
-            return false;
-        }
-        s.set_floatTest(2.99f);
-
-        double pD = s.get_doubleTest();
-        if (pD != 2.05) {
-            return false;
-        }
-        s.set_doubleTest(3.05);
-
-        byte pC = s.get_charTest();
-        if (pC != -8) {
-            return false;
-        }
-        s.set_charTest((byte)-16);
-
-        short pS = s.get_shortTest();
-        if (pS != -16) {
-            return false;
-        }
-        s.set_shortTest((short)-32);
-
-        int pI = s.get_intTest();
-        if (pI != -32) {
-            return false;
-        }
-        s.set_intTest(-64);
-
-        long pL = s.get_longTest();
-        if (pL != 17179869184l) {
-            return false;
-        }
-        s.set_longTest(17179869185l);
-
-        long puL = s.get_ulongTest();
-        if (puL != 4611686018427387904L) {
-            return false;
-        }
-        s.set_ulongTest(4611686018427387903L);
-
-
-        long pLL = s.get_longlongTest();
-        if (pLL != 68719476736L) {
-            return false;
-        }
-        s.set_longlongTest(68719476735L);
-
-        long pu64 = s.get_uint64_tTest();
-        if (pu64 != 117179869184l) {
-            return false;
-        }
-        s.set_uint64_tTest(117179869185l);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            // initializeGlobals failed
-            result = -1;
-        } else {
-            s.invoke_primitives_test(0, 0);
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rsdebug.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rsdebug.java
deleted file mode 100644
index 00dbaf5..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rsdebug.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rsdebug extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rsdebug(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsDebug", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rsdebug s = new ScriptC_rsdebug(pRS, mRes, R.raw.rsdebug);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rsdebug(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rstime.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rstime.java
deleted file mode 100644
index 5b4c399..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rstime.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rstime extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTime", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rstime(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rstypes.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rstypes.java
deleted file mode 100644
index 72a97c9..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UT_rstypes.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rstypes extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstypes(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTypes", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstypes s = new ScriptC_rstypes(pRS, mRes, R.raw.rstypes);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rstypes(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UnitTest.java
deleted file mode 100644
index b62e535..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/UnitTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v11;
-import android.content.Context;
-import android.renderscript.RenderScript.RSMessageHandler;
-import android.util.Log;
-
-public class UnitTest extends Thread {
-    public String name;
-    public int result;
-    private ScriptField_ListAllocs_s.Item mItem;
-    private RSTestCore mRSTC;
-    private boolean msgHandled;
-    protected Context mCtx;
-
-    /* These constants must match those in shared.rsh */
-    public static final int RS_MSG_TEST_PASSED = 100;
-    public static final int RS_MSG_TEST_FAILED = 101;
-
-    private static int numTests = 0;
-    public int testID;
-
-    protected UnitTest(RSTestCore rstc, String n, int initResult, Context ctx) {
-        super();
-        mRSTC = rstc;
-        name = n;
-        msgHandled = false;
-        mCtx = ctx;
-        result = initResult;
-        testID = numTests++;
-    }
-
-    protected UnitTest(RSTestCore rstc, String n, Context ctx) {
-        this(rstc, n, 0, ctx);
-    }
-
-    protected UnitTest(RSTestCore rstc, Context ctx) {
-        this (rstc, "<Unknown>", ctx);
-    }
-
-    protected UnitTest(Context ctx) {
-        this (null, ctx);
-    }
-
-    protected RSMessageHandler mRsMessage = new RSMessageHandler() {
-        public void run() {
-            if (result == 0) {
-                switch (mID) {
-                    case RS_MSG_TEST_PASSED:
-                        result = 1;
-                        break;
-                    case RS_MSG_TEST_FAILED:
-                        result = -1;
-                        break;
-                    default:
-                        android.util.Log.v("RenderScript", "Unit test got unexpected message");
-                        return;
-                }
-            }
-
-            if (mItem != null) {
-                mItem.result = result;
-                msgHandled = true;
-                try {
-                    mRSTC.refreshTestResults();
-                }
-                catch (IllegalStateException e) {
-                    /* Ignore the case where our message receiver has been
-                       disconnected. This happens when we leave the application
-                       before it finishes running all of the unit tests. */
-                }
-            }
-        }
-    };
-
-    public void waitForMessage() {
-        while (!msgHandled) {
-            yield();
-        }
-    }
-
-    public void setItem(ScriptField_ListAllocs_s.Item item) {
-        mItem = item;
-    }
-
-    public void run() {
-        /* This method needs to be implemented for each subclass */
-        if (mRSTC != null) {
-            mRSTC.refreshTestResults();
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/fp_mad.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/fp_mad.rs
deleted file mode 100644
index b6f2b2a6..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/fp_mad.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "shared.rsh"
-
-const int TEST_COUNT = 1;
-
-static float data_f1[1025];
-static float4 data_f4[1025];
-
-static void test_mad4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 80); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = (data_f4[i] * 0.02f +
-                          data_f4[i+1] * 0.04f +
-                          data_f4[i+2] * 0.05f +
-                          data_f4[i+3] * 0.1f +
-                          data_f4[i+4] * 0.2f +
-                          data_f4[i+5] * 0.2f +
-                          data_f4[i+6] * 0.1f +
-                          data_f4[i+7] * 0.05f +
-                          data_f4[i+8] * 0.04f +
-                          data_f4[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad4 M ops", 1000.f / time);
-}
-
-static void test_mad(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 20); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = (data_f1[i] * 0.02f +
-                          data_f1[i+1] * 0.04f +
-                          data_f1[i+2] * 0.05f +
-                          data_f1[i+3] * 0.1f +
-                          data_f1[i+4] * 0.2f +
-                          data_f1[i+5] * 0.2f +
-                          data_f1[i+6] * 0.1f +
-                          data_f1[i+7] * 0.05f +
-                          data_f1[i+8] * 0.04f +
-                          data_f1[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad M ops", 1000.f / time);
-}
-
-static void test_norm(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = normalize(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_norm M ops", 10.f / time);
-}
-
-static void test_sincos4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10 / 4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = sin(data_f4[i]) * cos(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos4 M ops", 10.f / time);
-}
-
-static void test_sincos(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = sin(data_f1[i]) * cos(data_f1[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos M ops", 10.f / time);
-}
-
-static void test_clamp(uint32_t index) {
-    start();
-
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp M ops", 100.f / time);
-
-    start();
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            if (data_f1[i] < -1.f) data_f1[i] = -1.f;
-            if (data_f1[i] > -1.f) data_f1[i] = 1.f;
-        }
-    }
-
-    time = end(index);
-    rsDebug("fp_clamp ref M ops", 100.f / time);
-}
-
-static void test_clamp4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100 /4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp4 M ops", 100.f / time);
-}
-
-void fp_mad_test(uint32_t index, int test_num) {
-    int x;
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f;
-        data_f4[x].x = (x & 0xf) * 0.1f;
-        data_f4[x].y = (x & 0xf0) * 0.1f;
-        data_f4[x].z = (x & 0x33) * 0.1f;
-        data_f4[x].w = (x & 0x77) * 0.1f;
-    }
-
-    test_mad4(index);
-    test_mad(index);
-
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].x = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].y = (x & 0xf0) * 0.1f + 1.f;
-        data_f4[x].z = (x & 0x33) * 0.1f + 1.f;
-        data_f4[x].w = (x & 0x77) * 0.1f + 1.f;
-    }
-
-    test_norm(index);
-    test_sincos4(index);
-    test_sincos(index);
-    test_clamp4(index);
-    test_clamp(index);
-
-    // TODO Actually verify test result accuracy
-    rsDebug("fp_mad_test PASSED", 0);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/math.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/math.rs
deleted file mode 100644
index 2867be1..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/math.rs
+++ /dev/null
@@ -1,348 +0,0 @@
-#include "shared.rsh"
-
-// Testing math library
-
-volatile float f1;
-volatile float2 f2;
-volatile float3 f3;
-volatile float4 f4;
-
-volatile int i1;
-volatile int2 i2;
-volatile int3 i3;
-volatile int4 i4;
-
-volatile uint ui1;
-volatile uint2 ui2;
-volatile uint3 ui3;
-volatile uint4 ui4;
-
-volatile short s1;
-volatile short2 s2;
-volatile short3 s3;
-volatile short4 s4;
-
-volatile ushort us1;
-volatile ushort2 us2;
-volatile ushort3 us3;
-volatile ushort4 us4;
-
-volatile char c1;
-volatile char2 c2;
-volatile char3 c3;
-volatile char4 c4;
-
-volatile uchar uc1;
-volatile uchar2 uc2;
-volatile uchar3 uc3;
-volatile uchar4 uc4;
-
-#define TEST_FN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f2 = fnc(f2);                   \
-    f3 = fnc(f3);                   \
-    f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (float*) &f1);     \
-    f2 = fnc(f2, (float2*) &f2);    \
-    f3 = fnc(f3, (float3*) &f3);    \
-    f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f2);               \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f1);               \
-    f3 = fnc(f3, f1);               \
-    f4 = fnc(f4, f1);
-
-#define TEST_FN_FUNC_FN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i2);               \
-    f3 = fnc(f3, i3);               \
-    f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i1);               \
-    f3 = fnc(f3, i1);               \
-    f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f2, f2);           \
-    f3 = fnc(f3, f3, f3);           \
-    f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_PIN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (int*) &i1);       \
-    f2 = fnc(f2, (int2*) &i2);      \
-    f3 = fnc(f3, (int3*) &i3);      \
-    f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, (int*) &i1);   \
-    f2 = fnc(f2, f2, (int2*) &i2);  \
-    f3 = fnc(f3, f3, (int3*) &i3);  \
-    f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    i1 = fnc(f1);                   \
-    i2 = fnc(f2);                   \
-    i3 = fnc(f3);                   \
-    i4 = fnc(f4);
-
-
-static bool test_fp_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_FN_FUNC_FN(acos);
-    TEST_FN_FUNC_FN(acosh);
-    TEST_FN_FUNC_FN(acospi);
-    TEST_FN_FUNC_FN(asin);
-    TEST_FN_FUNC_FN(asinh);
-    TEST_FN_FUNC_FN(asinpi);
-    TEST_FN_FUNC_FN(atan);
-    TEST_FN_FUNC_FN_FN(atan2);
-    TEST_FN_FUNC_FN(atanh);
-    TEST_FN_FUNC_FN(atanpi);
-    TEST_FN_FUNC_FN_FN(atan2pi);
-    TEST_FN_FUNC_FN(cbrt);
-    TEST_FN_FUNC_FN(ceil);
-    TEST_FN_FUNC_FN_FN(copysign);
-    TEST_FN_FUNC_FN(cos);
-    TEST_FN_FUNC_FN(cosh);
-    TEST_FN_FUNC_FN(cospi);
-    TEST_FN_FUNC_FN(erfc);
-    TEST_FN_FUNC_FN(erf);
-    TEST_FN_FUNC_FN(exp);
-    TEST_FN_FUNC_FN(exp2);
-    TEST_FN_FUNC_FN(exp10);
-    TEST_FN_FUNC_FN(expm1);
-    TEST_FN_FUNC_FN(fabs);
-    TEST_FN_FUNC_FN_FN(fdim);
-    TEST_FN_FUNC_FN(floor);
-    TEST_FN_FUNC_FN_FN_FN(fma);
-    TEST_FN_FUNC_FN_FN(fmax);
-    TEST_FN_FUNC_FN_F(fmax);
-    TEST_FN_FUNC_FN_FN(fmin);
-    TEST_FN_FUNC_FN_F(fmin);
-    TEST_FN_FUNC_FN_FN(fmod);
-    TEST_FN_FUNC_FN_PFN(fract);
-    TEST_FN_FUNC_FN_PIN(frexp);
-    TEST_FN_FUNC_FN_FN(hypot);
-    TEST_IN_FUNC_FN(ilogb);
-    TEST_FN_FUNC_FN_IN(ldexp);
-    TEST_FN_FUNC_FN_I(ldexp);
-    TEST_FN_FUNC_FN(lgamma);
-    TEST_FN_FUNC_FN_PIN(lgamma);
-    TEST_FN_FUNC_FN(log);
-    TEST_FN_FUNC_FN(log2);
-    TEST_FN_FUNC_FN(log10);
-    TEST_FN_FUNC_FN(log1p);
-    TEST_FN_FUNC_FN(logb);
-    TEST_FN_FUNC_FN_FN_FN(mad);
-    TEST_FN_FUNC_FN_PFN(modf);
-    // nan
-    TEST_FN_FUNC_FN_FN(nextafter);
-    TEST_FN_FUNC_FN_FN(pow);
-    TEST_FN_FUNC_FN_IN(pown);
-    TEST_FN_FUNC_FN_FN(powr);
-    TEST_FN_FUNC_FN_FN(remainder);
-    TEST_FN_FUNC_FN_FN_PIN(remquo);
-    TEST_FN_FUNC_FN(rint);
-    TEST_FN_FUNC_FN_IN(rootn);
-    TEST_FN_FUNC_FN(round);
-    TEST_FN_FUNC_FN(rsqrt);
-    TEST_FN_FUNC_FN(sin);
-    TEST_FN_FUNC_FN_PFN(sincos);
-    TEST_FN_FUNC_FN(sinh);
-    TEST_FN_FUNC_FN(sinpi);
-    TEST_FN_FUNC_FN(sqrt);
-    TEST_FN_FUNC_FN(tan);
-    TEST_FN_FUNC_FN(tanh);
-    TEST_FN_FUNC_FN(tanpi);
-    TEST_FN_FUNC_FN(tgamma);
-    TEST_FN_FUNC_FN(trunc);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_fp_math FAILED", time);
-    }
-    else {
-        rsDebug("test_fp_math PASSED", time);
-    }
-
-    return failed;
-}
-
-#define DECL_INT(prefix)            \
-volatile char prefix##_c_1 = 1;     \
-volatile char2 prefix##_c_2 = 1;    \
-volatile char3 prefix##_c_3 = 1;    \
-volatile char4 prefix##_c_4 = 1;    \
-volatile uchar prefix##_uc_1 = 1;   \
-volatile uchar2 prefix##_uc_2 = 1;  \
-volatile uchar3 prefix##_uc_3 = 1;  \
-volatile uchar4 prefix##_uc_4 = 1;  \
-volatile short prefix##_s_1 = 1;    \
-volatile short2 prefix##_s_2 = 1;   \
-volatile short3 prefix##_s_3 = 1;   \
-volatile short4 prefix##_s_4 = 1;   \
-volatile ushort prefix##_us_1 = 1;  \
-volatile ushort2 prefix##_us_2 = 1; \
-volatile ushort3 prefix##_us_3 = 1; \
-volatile ushort4 prefix##_us_4 = 1; \
-volatile int prefix##_i_1 = 1;      \
-volatile int2 prefix##_i_2 = 1;     \
-volatile int3 prefix##_i_3 = 1;     \
-volatile int4 prefix##_i_4 = 1;     \
-volatile uint prefix##_ui_1 = 1;    \
-volatile uint2 prefix##_ui_2 = 1;   \
-volatile uint3 prefix##_ui_3 = 1;   \
-volatile uint4 prefix##_ui_4 = 1;   \
-volatile long prefix##_l_1 = 1;     \
-volatile ulong prefix##_ul_1 = 1;
-
-#define TEST_INT_OP_TYPE(op, type)                      \
-rsDebug("Testing " #op " for " #type "1", i++);         \
-res_##type##_1 = src1_##type##_1 op src2_##type##_1;    \
-rsDebug("Testing " #op " for " #type "2", i++);         \
-res_##type##_2 = src1_##type##_2 op src2_##type##_2;    \
-rsDebug("Testing " #op " for " #type "3", i++);         \
-res_##type##_3 = src1_##type##_3 op src2_##type##_3;    \
-rsDebug("Testing " #op " for " #type "4", i++);         \
-res_##type##_4 = src1_##type##_4 op src2_##type##_4;
-
-#define TEST_INT_OP(op)                     \
-TEST_INT_OP_TYPE(op, c)                     \
-TEST_INT_OP_TYPE(op, uc)                    \
-TEST_INT_OP_TYPE(op, s)                     \
-TEST_INT_OP_TYPE(op, us)                    \
-TEST_INT_OP_TYPE(op, i)                     \
-TEST_INT_OP_TYPE(op, ui)                    \
-rsDebug("Testing " #op " for l1", i++);     \
-res_l_1 = src1_l_1 op src2_l_1;             \
-rsDebug("Testing " #op " for ul1", i++);    \
-res_ul_1 = src1_ul_1 op src2_ul_1;
-
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
-
-static bool test_basic_operators() {
-    bool failed = false;
-    int i = 0;
-
-    TEST_INT_OP(+);
-    TEST_INT_OP(-);
-    TEST_INT_OP(*);
-    TEST_INT_OP(/);
-    TEST_INT_OP(%);
-    TEST_INT_OP(<<);
-    TEST_INT_OP(>>);
-
-    if (failed) {
-        rsDebug("test_basic_operators FAILED", 0);
-    }
-    else {
-        rsDebug("test_basic_operators PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define TEST_CVT(to, from, type)                        \
-rsDebug("Testing convert from " #from " to " #to, 0);   \
-to##1 = from##1;                                        \
-to##2 = convert_##type##2(from##2);                     \
-to##3 = convert_##type##3(from##3);                     \
-to##4 = convert_##type##4(from##4);
-
-#define TEST_CVT_MATRIX(to, type)   \
-TEST_CVT(to, c, type);              \
-TEST_CVT(to, uc, type);             \
-TEST_CVT(to, s, type);              \
-TEST_CVT(to, us, type);             \
-TEST_CVT(to, i, type);              \
-TEST_CVT(to, ui, type);             \
-TEST_CVT(to, f, type);              \
-
-static bool test_convert() {
-    bool failed = false;
-
-    TEST_CVT_MATRIX(c, char);
-    TEST_CVT_MATRIX(uc, uchar);
-    TEST_CVT_MATRIX(s, short);
-    TEST_CVT_MATRIX(us, ushort);
-    TEST_CVT_MATRIX(i, int);
-    TEST_CVT_MATRIX(ui, uint);
-    TEST_CVT_MATRIX(f, float);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define INIT_PREFIX_TYPE(prefix, type)  \
-prefix##_##type##_1 = 1;                \
-prefix##_##type##_2.x = 1;              \
-prefix##_##type##_2.y = 1;              \
-prefix##_##type##_3.x = 1;              \
-prefix##_##type##_3.y = 1;              \
-prefix##_##type##_3.z = 1;              \
-prefix##_##type##_4.x = 1;              \
-prefix##_##type##_4.y = 1;              \
-prefix##_##type##_4.z = 1;              \
-prefix##_##type##_4.w = 1;
-
-#define INIT_TYPE(type)         \
-INIT_PREFIX_TYPE(src1, type)    \
-INIT_PREFIX_TYPE(src2, type)    \
-INIT_PREFIX_TYPE(res, type)
-
-#define INIT_ALL    \
-INIT_TYPE(c);       \
-INIT_TYPE(uc);      \
-INIT_TYPE(s);       \
-INIT_TYPE(us);      \
-INIT_TYPE(i);       \
-INIT_TYPE(ui);
-
-void math_test(uint32_t index, int test_num) {
-    bool failed = false;
-    INIT_ALL;
-    failed |= test_convert();
-    failed |= test_fp_math(index);
-    failed |= test_basic_operators();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/primitives.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/primitives.rs
deleted file mode 100644
index ce451da..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/primitives.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool test_primitive_types(uint32_t index) {
-    bool failed = false;
-    start();
-
-    _RS_ASSERT(floatTest == 2.99f);
-    _RS_ASSERT(doubleTest == 3.05);
-    _RS_ASSERT(charTest == -16);
-    _RS_ASSERT(shortTest == -32);
-    _RS_ASSERT(intTest == -64);
-    _RS_ASSERT(longTest == 17179869185l);
-    _RS_ASSERT(longlongTest == 68719476735l);
-
-    _RS_ASSERT(ucharTest == 8);
-    _RS_ASSERT(ushortTest == 16);
-    _RS_ASSERT(uintTest == 32);
-    _RS_ASSERT(ulongTest == 4611686018427387903L);
-    _RS_ASSERT(int64_tTest == -17179869184l);
-    _RS_ASSERT(uint64_tTest == 117179869185l);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_primitives FAILED", time);
-    }
-    else {
-        rsDebug("test_primitives PASSED", time);
-    }
-
-    return failed;
-}
-
-void primitives_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_primitive_types(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rsdebug.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rsdebug.rs
deleted file mode 100644
index f7942a5..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rsdebug.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    // For this reason, none of the outputs are actually checked.
-
-    rsDebug("floatTest", floatTest);
-    rsDebug("doubleTest", doubleTest);
-    rsDebug("charTest", charTest);
-    rsDebug("shortTest", shortTest);
-    rsDebug("intTest", intTest);
-    rsDebug("longTest", longTest);
-    rsDebug("longlongTest", longlongTest);
-
-    rsDebug("ucharTest", ucharTest);
-    rsDebug("ushortTest", ushortTest);
-    rsDebug("uintTest", uintTest);
-    rsDebug("ulongTest", ulongTest);
-    rsDebug("int64_tTest", int64_tTest);
-    rsDebug("uint64_tTest", uint64_tTest);
-
-    return failed;
-}
-
-void test_rsdebug(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rsdebug_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rsdebug_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rslist.rs
deleted file mode 100644
index 5b2501f..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rslist.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (C) 2009 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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_v11)
-
-#include "rs_graphics.rsh"
-
-float gDY;
-
-rs_font gFont;
-
-typedef struct ListAllocs_s {
-    rs_allocation text;
-    int result;
-} ListAllocs;
-
-ListAllocs *gList;
-
-void init() {
-    gDY = 0.0f;
-}
-
-int textPos = 0;
-
-int root(int launchID) {
-
-    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-    rsgClearDepth(1.0f);
-
-    textPos -= (int)gDY*2;
-    gDY *= 0.95;
-
-    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-    rsgBindFont(gFont);
-
-    rs_allocation listAlloc;
-    rsSetObject(&listAlloc, rsGetAllocation(gList));
-    int allocSize = rsAllocationGetDimX(listAlloc);
-
-    int width = rsgGetWidth();
-    int height = rsgGetHeight();
-
-    int itemHeight = 80;
-    int totalItemHeight = itemHeight * allocSize;
-
-    /* Prevent scrolling above the top of the list */
-    int firstItem = height - totalItemHeight;
-    if (firstItem < 0) {
-        firstItem = 0;
-    }
-
-    /* Prevent scrolling past the last line of the list */
-    int lastItem = -1 * (totalItemHeight - height);
-    if (lastItem > 0) {
-        lastItem = 0;
-    }
-
-    if (textPos > firstItem) {
-        textPos = firstItem;
-    }
-    else if (textPos < lastItem) {
-        textPos = lastItem;
-    }
-
-    int currentYPos = itemHeight + textPos;
-
-    for(int i = 0; i < allocSize; i ++) {
-        if(currentYPos - itemHeight > height) {
-            break;
-        }
-
-        if(currentYPos > 0) {
-            switch(gList[i].result) {
-                case 1: /* Passed */
-                    rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f);
-                    break;
-                case -1: /* Failed */
-                    rsgFontColor(0.9f, 0.5f, 0.5f, 1.0f);
-                    break;
-                case 0: /* Still Testing */
-                    rsgFontColor(0.9f, 0.9f, 0.5f, 1.0f);
-                    break;
-                default: /* Unknown */
-                    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-                    break;
-            }
-            rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
-            rsgDrawText(gList[i].text, 30, currentYPos - 32);
-        }
-        currentYPos += itemHeight;
-    }
-
-    return 10;
-}
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rstime.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rstime.rs
deleted file mode 100644
index 5e3e078..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rstime.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "shared.rsh"
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_time_t curTime = rsTime(0);
-    rs_tm tm;
-    rsDebug("curTime", curTime);
-
-    rsLocaltime(&tm, &curTime);
-
-    rsDebug("tm.tm_sec", tm.tm_sec);
-    rsDebug("tm.tm_min", tm.tm_min);
-    rsDebug("tm.tm_hour", tm.tm_hour);
-    rsDebug("tm.tm_mday", tm.tm_mday);
-    rsDebug("tm.tm_mon", tm.tm_mon);
-    rsDebug("tm.tm_year", tm.tm_year);
-    rsDebug("tm.tm_wday", tm.tm_wday);
-    rsDebug("tm.tm_yday", tm.tm_yday);
-    rsDebug("tm.tm_isdst", tm.tm_isdst);
-
-    // Test a specific time (only valid for PST localtime)
-    curTime = 1294438893;
-    rsLocaltime(&tm, &curTime);
-
-    _RS_ASSERT(tm.tm_sec == 33);
-    _RS_ASSERT(tm.tm_min == 21);
-    _RS_ASSERT(tm.tm_hour == 14);
-    _RS_ASSERT(tm.tm_mday == 7);
-    _RS_ASSERT(tm.tm_mon == 0);
-    _RS_ASSERT(tm.tm_year == 111);
-    _RS_ASSERT(tm.tm_wday == 5);
-    _RS_ASSERT(tm.tm_yday == 6);
-    _RS_ASSERT(tm.tm_isdst == 0);
-
-    return failed;
-}
-
-void test_rstime(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstime_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstime_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rstypes.rs
deleted file mode 100644
index f3bf244..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/rstypes.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_element elementTest;
-rs_type typeTest;
-rs_allocation allocationTest;
-rs_sampler samplerTest;
-rs_script scriptTest;
-rs_mesh meshTest;
-rs_program_fragment program_fragmentTest;
-rs_program_vertex program_vertexTest;
-rs_program_raster program_rasterTest;
-rs_program_store program_storeTest;
-rs_font fontTest;
-
-rs_matrix4x4 matrix4x4Test;
-rs_matrix3x3 matrix3x3Test;
-rs_matrix2x2 matrix2x2Test;
-
-struct my_struct {
-    int i;
-    rs_font fontTestStruct;
-};
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_matrix4x4 matrix4x4TestLocal;
-    rs_matrix3x3 matrix3x3TestLocal;
-    rs_matrix2x2 matrix2x2TestLocal;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    rs_element elementTestLocal;
-    rs_type typeTestLocal;
-    rs_allocation allocationTestLocal;
-    rs_sampler samplerTestLocal;
-    rs_script scriptTestLocal;
-    rs_mesh meshTestLocal;
-    rs_program_fragment program_fragmentTestLocal;
-    rs_program_vertex program_vertexTestLocal;
-    rs_program_raster program_rasterTestLocal;
-    rs_program_store program_storeTestLocal;
-    rs_font fontTestLocal;
-
-    rs_font fontTestLocalArray[4];
-
-    rs_font fontTestLocalPreInit = fontTest;
-
-    struct my_struct structTest;
-
-    rsSetObject(&fontTestLocal, fontTest);
-    //allocationTestLocal = allocationTest;
-
-    rsSetObject(&fontTest, fontTestLocal);
-    //allocationTest = allocationTestLocal;
-
-    /*for (int i = 0; i < 4; i++) {
-        rsSetObject(&fontTestLocalArray[i], fontTestLocal);
-    }*/
-
-    /*rsSetObject(&fontTest, fontTestLocalArray[3]);*/
-
-    return failed;
-}
-
-void test_rstypes(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstypes_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstypes_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/shared.rsh b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/shared.rsh
deleted file mode 100644
index 6d34481..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/shared.rsh
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_v11)
-
-typedef struct TestResult_s {
-    rs_allocation name;
-    bool pass;
-    float score;
-    int64_t time;
-} TestResult;
-//TestResult *g_results;
-
-static int64_t g_time;
-
-static void start(void) {
-    g_time = rsUptimeMillis();
-}
-
-static float end(uint32_t idx) {
-    int64_t t = rsUptimeMillis() - g_time;
-    //g_results[idx].time = t;
-    //rsDebug("test time", (int)t);
-    return ((float)t) / 1000.f;
-}
-
-#define _RS_ASSERT(b) \
-do { \
-    if (!(b)) { \
-        failed = true; \
-        rsDebug(#b " FAILED", 0); \
-    } \
-\
-} while (0)
-
-/* These constants must match those in UnitTest.java */
-static const int RS_MSG_TEST_PASSED = 100;
-static const int RS_MSG_TEST_FAILED = 101;
-
diff --git a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/test_root.rs b/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/test_root.rs
deleted file mode 100644
index 6dc83ba..0000000
--- a/tests/RenderScriptTests/tests_v11/src/com/android/rs/test/test_root.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-
-typedef struct TestResult {
-    rs_allocation name;
-    bool pass;
-    float score;
-} TestResult_t;
-TestResult_t *results;
-
-int root() {
-
-    return 0;
-}
-
-
diff --git a/tests/RenderScriptTests/tests_v14/Android.mk b/tests/RenderScriptTests/tests_v14/Android.mk
deleted file mode 100644
index a4386a44..0000000
--- a/tests/RenderScriptTests/tests_v14/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_PACKAGE_NAME := RSTest_v14
-LOCAL_SDK_VERSION := 14
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/tests_v14/AndroidManifest.xml b/tests/RenderScriptTests/tests_v14/AndroidManifest.xml
deleted file mode 100644
index 1cd9bbd..0000000
--- a/tests/RenderScriptTests/tests_v14/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.rs.test_v14">
-    <uses-sdk android:minSdkVersion="14" />
-    <application 
-        android:label="_RS_Test_v14"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="RSTest_v14"
-                  android:screenOrientation="portrait">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/tests_v14/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/tests_v14/res/drawable-nodpi/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/tests_v14/res/drawable-nodpi/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTestCore.java
deleted file mode 100644
index f1e81a4..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTestCore.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2008-2011 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.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.ListIterator;
-import java.util.Timer;
-import java.util.TimerTask;
-
-
-public class RSTestCore {
-    int mWidth;
-    int mHeight;
-    Context mCtx;
-
-    public RSTestCore(Context ctx) {
-        mCtx = ctx;
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-
-    private Font mFont;
-    ScriptField_ListAllocs_s mListAllocs;
-    int mLastX;
-    int mLastY;
-    private ScriptC_rslist mScript;
-
-    private ArrayList<UnitTest> unitTests;
-    private ListIterator<UnitTest> test_iter;
-    private UnitTest activeTest;
-    private boolean stopTesting;
-
-    /* Periodic timer for ensuring future tests get scheduled */
-    private Timer mTimer;
-    public static final int RS_TIMER_PERIOD = 100;
-
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-        mWidth = width;
-        mHeight = height;
-        stopTesting = false;
-
-        mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist);
-
-        unitTests = new ArrayList<UnitTest>();
-
-        unitTests.add(new UT_primitives(this, mRes, mCtx));
-        unitTests.add(new UT_vector(this, mRes, mCtx));
-        unitTests.add(new UT_rsdebug(this, mRes, mCtx));
-        unitTests.add(new UT_rstime(this, mRes, mCtx));
-        unitTests.add(new UT_rstypes(this, mRes, mCtx));
-        unitTests.add(new UT_alloc(this, mRes, mCtx));
-        unitTests.add(new UT_refcount(this, mRes, mCtx));
-        unitTests.add(new UT_foreach(this, mRes, mCtx));
-        unitTests.add(new UT_math(this, mRes, mCtx));
-        unitTests.add(new UT_fp_mad(this, mRes, mCtx));
-        /*
-        unitTests.add(new UnitTest(null, "<Pass>", 1));
-        unitTests.add(new UnitTest());
-        unitTests.add(new UnitTest(null, "<Fail>", -1));
-
-        for (int i = 0; i < 20; i++) {
-            unitTests.add(new UnitTest(null, "<Pass>", 1));
-        }
-        */
-
-        UnitTest [] uta = new UnitTest[unitTests.size()];
-        uta = unitTests.toArray(uta);
-
-        mListAllocs = new ScriptField_ListAllocs_s(mRS, uta.length);
-        for (int i = 0; i < uta.length; i++) {
-            ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
-            listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
-            listElem.result = uta[i].result;
-            mListAllocs.set(listElem, i, false);
-            uta[i].setItem(listElem);
-        }
-
-        mListAllocs.copyAll();
-
-        mScript.bind_gList(mListAllocs);
-
-        mFont = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8);
-        mScript.set_gFont(mFont);
-
-        mRS.bindRootScript(mScript);
-
-        test_iter = unitTests.listIterator();
-        refreshTestResults(); /* Kick off the first test */
-
-        TimerTask pTask = new TimerTask() {
-            public void run() {
-                refreshTestResults();
-            }
-        };
-
-        mTimer = new Timer();
-        mTimer.schedule(pTask, RS_TIMER_PERIOD, RS_TIMER_PERIOD);
-    }
-
-    public void checkAndRunNextTest() {
-        if (activeTest != null) {
-            if (!activeTest.isAlive()) {
-                /* Properly clean up on our last test */
-                try {
-                    activeTest.join();
-                }
-                catch (InterruptedException e) {
-                }
-                activeTest = null;
-            }
-        }
-
-        if (!stopTesting && activeTest == null) {
-            if (test_iter.hasNext()) {
-                activeTest = test_iter.next();
-                activeTest.start();
-                /* This routine will only get called once when a new test
-                 * should start running. The message handler in UnitTest.java
-                 * ensures this. */
-            }
-            else {
-                if (mTimer != null) {
-                    mTimer.cancel();
-                    mTimer.purge();
-                    mTimer = null;
-                }
-            }
-        }
-    }
-
-    public void refreshTestResults() {
-        checkAndRunNextTest();
-
-        if (mListAllocs != null && mScript != null && mRS != null) {
-            mListAllocs.copyAll();
-
-            mScript.bind_gList(mListAllocs);
-            mRS.bindRootScript(mScript);
-        }
-    }
-
-    public void cleanup() {
-        stopTesting = true;
-        UnitTest t = activeTest;
-
-        /* Stop periodic refresh of testing */
-        if (mTimer != null) {
-            mTimer.cancel();
-            mTimer.purge();
-            mTimer = null;
-        }
-
-        /* Wait to exit until we finish the current test */
-        if (t != null) {
-            try {
-                t.join();
-            }
-            catch (InterruptedException e) {
-            }
-            t = null;
-        }
-
-    }
-
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-    }
-
-    public void onActionDown(int x, int y) {
-        mScript.set_gDY(0.0f);
-        mLastX = x;
-        mLastY = y;
-        refreshTestResults();
-    }
-
-    public void onActionMove(int x, int y) {
-        int dx = mLastX - x;
-        int dy = mLastY - y;
-
-        if (Math.abs(dy) <= 2) {
-            dy = 0;
-        }
-
-        mScript.set_gDY(dy);
-
-        mLastX = x;
-        mLastY = y;
-        refreshTestResults();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTestView.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTestView.java
deleted file mode 100644
index 40192e4..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTestView.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test_v14;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class RSTestView extends RSSurfaceView {
-
-    private Context mCtx;
-
-    public RSTestView(Context context) {
-        super(context);
-        mCtx = context;
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private RSTestCore mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new RSTestCore(mCtx);
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if(mRS != null) {
-            mRender.cleanup();
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event)
-    {
-        return super.onKeyDown(keyCode, event);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        boolean ret = false;
-        int act = ev.getAction();
-        if (act == ev.ACTION_DOWN) {
-            mRender.onActionDown((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-        else if (act == ev.ACTION_MOVE) {
-            mRender.onActionMove((int)ev.getX(), (int)ev.getY());
-            ret = true;
-        }
-
-        return ret;
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTest_v14.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTest_v14.java
deleted file mode 100644
index da09691..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/RSTest_v14.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008 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.rs.test_v14;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import java.lang.Runtime;
-
-public class RSTest_v14 extends Activity {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "RSTest_v14";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private RSTestView mView;
-
-    // get the current looper (from your Activity UI thread for instance
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new RSTestView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity loses focus
-        super.onPause();
-        mView.pause();
-    }
-
-    @Override
-    protected void onStop() {
-        // Actually kill the app if we are stopping. We don't want to
-        // continue/resume this test ever. It should always start fresh.
-        finish();
-        super.onStop();
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_alloc.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_alloc.java
deleted file mode 100644
index da42b29..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_alloc.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_alloc extends UnitTest {
-    private Resources mRes;
-
-    protected UT_alloc(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Alloc", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_alloc s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        int Z = 0;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        s.set_dimZ(Z);
-        typeBuilder.setX(X).setY(Y);
-        Allocation A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
-
-        typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        typeBuilder.setX(X).setY(Y).setFaces(true);
-        Allocation AFaces = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aFaces(AFaces);
-        typeBuilder.setFaces(false).setMipmaps(true);
-        Allocation ALOD = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aLOD(ALOD);
-        typeBuilder.setFaces(true).setMipmaps(true);
-        Allocation AFacesLOD = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_aFacesLOD(AFacesLOD);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_alloc s = new ScriptC_alloc(pRS, mRes, R.raw.alloc);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.invoke_alloc_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_foreach.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_foreach.java
deleted file mode 100644
index aeb5bb7..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_foreach.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_foreach extends UnitTest {
-    private Resources mRes;
-    private Allocation A;
-
-    protected UT_foreach(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "ForEach", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_foreach s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 5;
-        int Y = 7;
-        s.set_dimX(X);
-        s.set_dimY(Y);
-        typeBuilder.setX(X).setY(Y);
-        A = Allocation.createTyped(RS, typeBuilder.create());
-        s.bind_a(A);
-
-        return;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_foreach s = new ScriptC_foreach(pRS, mRes, R.raw.foreach);
-        pRS.setMessageHandler(mRsMessage);
-        initializeGlobals(pRS, s);
-        s.forEach_root(A);
-        s.invoke_foreach_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_fp_mad.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_fp_mad.java
deleted file mode 100644
index 239496a..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_fp_mad.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_fp_mad extends UnitTest {
-    private Resources mRes;
-
-    protected UT_fp_mad(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Fp_Mad", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_fp_mad s = new ScriptC_fp_mad(pRS, mRes, R.raw.fp_mad);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_fp_mad_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_math.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_math.java
deleted file mode 100644
index 7b135c4..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_math.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_math extends UnitTest {
-    private Resources mRes;
-
-    protected UT_math(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Math", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_math s = new ScriptC_math(pRS, mRes, R.raw.math);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_math_test(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_primitives.java
deleted file mode 100644
index d3c56f3..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_primitives.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_primitives extends UnitTest {
-    private Resources mRes;
-
-    protected UT_primitives(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Primitives", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_primitives s) {
-        float pF = s.get_floatTest();
-        if (pF != 1.99f) {
-            return false;
-        }
-        s.set_floatTest(2.99f);
-
-        double pD = s.get_doubleTest();
-        if (pD != 2.05) {
-            return false;
-        }
-        s.set_doubleTest(3.05);
-
-        byte pC = s.get_charTest();
-        if (pC != -8) {
-            return false;
-        }
-        s.set_charTest((byte)-16);
-
-        short pS = s.get_shortTest();
-        if (pS != -16) {
-            return false;
-        }
-        s.set_shortTest((short)-32);
-
-        int pI = s.get_intTest();
-        if (pI != -32) {
-            return false;
-        }
-        s.set_intTest(-64);
-
-        long pL = s.get_longTest();
-        if (pL != 17179869184l) {
-            return false;
-        }
-        s.set_longTest(17179869185l);
-
-        long puL = s.get_ulongTest();
-        if (puL != 4611686018427387904L) {
-            return false;
-        }
-        s.set_ulongTest(4611686018427387903L);
-
-
-        long pLL = s.get_longlongTest();
-        if (pLL != 68719476736L) {
-            return false;
-        }
-        s.set_longlongTest(68719476735L);
-
-        long pu64 = s.get_uint64_tTest();
-        if (pu64 != 117179869184l) {
-            return false;
-        }
-        s.set_uint64_tTest(117179869185l);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            // initializeGlobals failed
-            result = -1;
-        } else {
-            s.invoke_primitives_test(0, 0);
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_refcount.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_refcount.java
deleted file mode 100644
index 05a516b..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_refcount.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_refcount extends UnitTest {
-    private Resources mRes;
-
-    protected UT_refcount(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Refcount", ctx);
-        mRes = res;
-    }
-
-    private void initializeGlobals(RenderScript RS, ScriptC_refcount s) {
-        Type.Builder typeBuilder = new Type.Builder(RS, Element.I32(RS));
-        int X = 500;
-        int Y = 700;
-        typeBuilder.setX(X).setY(Y);
-        Allocation A = Allocation.createTyped(RS, typeBuilder.create());
-        s.set_globalA(A);
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        pRS.setMessageHandler(mRsMessage);
-        ScriptC_refcount s = new ScriptC_refcount(pRS, mRes, R.raw.refcount);
-        initializeGlobals(pRS, s);
-        s.invoke_refcount_test();
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rsdebug.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rsdebug.java
deleted file mode 100644
index 95e92ee..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rsdebug.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rsdebug extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rsdebug(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsDebug", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rsdebug s = new ScriptC_rsdebug(pRS, mRes, R.raw.rsdebug);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rsdebug(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rstime.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rstime.java
deleted file mode 100644
index a72ede9..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rstime.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rstime extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstime(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTime", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rstime(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rstypes.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rstypes.java
deleted file mode 100644
index ab96867..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_rstypes.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_rstypes extends UnitTest {
-    private Resources mRes;
-
-    protected UT_rstypes(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "rsTypes", ctx);
-        mRes = res;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_rstypes s = new ScriptC_rstypes(pRS, mRes, R.raw.rstypes);
-        pRS.setMessageHandler(mRsMessage);
-        s.invoke_test_rstypes(0, 0);
-        pRS.finish();
-        waitForMessage();
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_vector.java
deleted file mode 100644
index 657413e..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UT_vector.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2011 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.rs.test_v14;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.renderscript.*;
-
-public class UT_vector extends UnitTest {
-    private Resources mRes;
-
-    protected UT_vector(RSTestCore rstc, Resources res, Context ctx) {
-        super(rstc, "Vector", ctx);
-        mRes = res;
-    }
-
-    private boolean initializeGlobals(ScriptC_vector s) {
-        Float2 F2 = s.get_f2();
-        if (F2.x != 1.0f || F2.y != 2.0f) {
-            return false;
-        }
-        F2.x = 2.99f;
-        F2.y = 3.99f;
-        s.set_f2(F2);
-
-        Float3 F3 = s.get_f3();
-        if (F3.x != 1.0f || F3.y != 2.0f || F3.z != 3.0f) {
-            return false;
-        }
-        F3.x = 2.99f;
-        F3.y = 3.99f;
-        F3.z = 4.99f;
-        s.set_f3(F3);
-
-        Float4 F4 = s.get_f4();
-        if (F4.x != 1.0f || F4.y != 2.0f || F4.z != 3.0f || F4.w != 4.0f) {
-            return false;
-        }
-        F4.x = 2.99f;
-        F4.y = 3.99f;
-        F4.z = 4.99f;
-        F4.w = 5.99f;
-        s.set_f4(F4);
-
-        Double2 D2 = s.get_d2();
-        if (D2.x != 1.0 || D2.y != 2.0) {
-            return false;
-        }
-        D2.x = 2.99;
-        D2.y = 3.99;
-        s.set_d2(D2);
-
-        Double3 D3 = s.get_d3();
-        if (D3.x != 1.0 || D3.y != 2.0 || D3.z != 3.0) {
-            return false;
-        }
-        D3.x = 2.99;
-        D3.y = 3.99;
-        D3.z = 4.99;
-        s.set_d3(D3);
-
-        Double4 D4 = s.get_d4();
-        if (D4.x != 1.0 || D4.y != 2.0 || D4.z != 3.0 || D4.w != 4.0) {
-            return false;
-        }
-        D4.x = 2.99;
-        D4.y = 3.99;
-        D4.z = 4.99;
-        D4.w = 5.99;
-        s.set_d4(D4);
-
-        Byte2 B2 = s.get_i8_2();
-        if (B2.x != 1 || B2.y != 2) {
-            return false;
-        }
-        B2.x = 2;
-        B2.y = 3;
-        s.set_i8_2(B2);
-
-        Byte3 B3 = s.get_i8_3();
-        if (B3.x != 1 || B3.y != 2 || B3.z != 3) {
-            return false;
-        }
-        B3.x = 2;
-        B3.y = 3;
-        B3.z = 4;
-        s.set_i8_3(B3);
-
-        Byte4 B4 = s.get_i8_4();
-        if (B4.x != 1 || B4.y != 2 || B4.z != 3 || B4.w != 4) {
-            return false;
-        }
-        B4.x = 2;
-        B4.y = 3;
-        B4.z = 4;
-        B4.w = 5;
-        s.set_i8_4(B4);
-
-        Short2 S2 = s.get_u8_2();
-        if (S2.x != 1 || S2.y != 2) {
-            return false;
-        }
-        S2.x = 2;
-        S2.y = 3;
-        s.set_u8_2(S2);
-
-        Short3 S3 = s.get_u8_3();
-        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
-            return false;
-        }
-        S3.x = 2;
-        S3.y = 3;
-        S3.z = 4;
-        s.set_u8_3(S3);
-
-        Short4 S4 = s.get_u8_4();
-        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
-            return false;
-        }
-        S4.x = 2;
-        S4.y = 3;
-        S4.z = 4;
-        S4.w = 5;
-        s.set_u8_4(S4);
-
-        S2 = s.get_i16_2();
-        if (S2.x != 1 || S2.y != 2) {
-            return false;
-        }
-        S2.x = 2;
-        S2.y = 3;
-        s.set_i16_2(S2);
-
-        S3 = s.get_i16_3();
-        if (S3.x != 1 || S3.y != 2 || S3.z != 3) {
-            return false;
-        }
-        S3.x = 2;
-        S3.y = 3;
-        S3.z = 4;
-        s.set_i16_3(S3);
-
-        S4 = s.get_i16_4();
-        if (S4.x != 1 || S4.y != 2 || S4.z != 3 || S4.w != 4) {
-            return false;
-        }
-        S4.x = 2;
-        S4.y = 3;
-        S4.z = 4;
-        S4.w = 5;
-        s.set_i16_4(S4);
-
-        Int2 I2 = s.get_u16_2();
-        if (I2.x != 1 || I2.y != 2) {
-            return false;
-        }
-        I2.x = 2;
-        I2.y = 3;
-        s.set_u16_2(I2);
-
-        Int3 I3 = s.get_u16_3();
-        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
-            return false;
-        }
-        I3.x = 2;
-        I3.y = 3;
-        I3.z = 4;
-        s.set_u16_3(I3);
-
-        Int4 I4 = s.get_u16_4();
-        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
-            return false;
-        }
-        I4.x = 2;
-        I4.y = 3;
-        I4.z = 4;
-        I4.w = 5;
-        s.set_u16_4(I4);
-
-        I2 = s.get_i32_2();
-        if (I2.x != 1 || I2.y != 2) {
-            return false;
-        }
-        I2.x = 2;
-        I2.y = 3;
-        s.set_i32_2(I2);
-
-        I3 = s.get_i32_3();
-        if (I3.x != 1 || I3.y != 2 || I3.z != 3) {
-            return false;
-        }
-        I3.x = 2;
-        I3.y = 3;
-        I3.z = 4;
-        s.set_i32_3(I3);
-
-        I4 = s.get_i32_4();
-        if (I4.x != 1 || I4.y != 2 || I4.z != 3 || I4.w != 4) {
-            return false;
-        }
-        I4.x = 2;
-        I4.y = 3;
-        I4.z = 4;
-        I4.w = 5;
-        s.set_i32_4(I4);
-
-        Long2 L2 = s.get_u32_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_u32_2(L2);
-
-        Long3 L3 = s.get_u32_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_u32_3(L3);
-
-        Long4 L4 = s.get_u32_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_u32_4(L4);
-
-        L2 = s.get_i64_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_i64_2(L2);
-
-        L3 = s.get_i64_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_i64_3(L3);
-
-        L4 = s.get_i64_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_i64_4(L4);
-
-        L2 = s.get_u64_2();
-        if (L2.x != 1 || L2.y != 2) {
-            return false;
-        }
-        L2.x = 2;
-        L2.y = 3;
-        s.set_u64_2(L2);
-
-        L3 = s.get_u64_3();
-        if (L3.x != 1 || L3.y != 2 || L3.z != 3) {
-            return false;
-        }
-        L3.x = 2;
-        L3.y = 3;
-        L3.z = 4;
-        s.set_u64_3(L3);
-
-        L4 = s.get_u64_4();
-        if (L4.x != 1 || L4.y != 2 || L4.z != 3 || L4.w != 4) {
-            return false;
-        }
-        L4.x = 2;
-        L4.y = 3;
-        L4.z = 4;
-        L4.w = 5;
-        s.set_u64_4(L4);
-
-        return true;
-    }
-
-    public void run() {
-        RenderScript pRS = RenderScript.create(mCtx);
-        ScriptC_vector s = new ScriptC_vector(pRS, mRes, R.raw.vector);
-        pRS.setMessageHandler(mRsMessage);
-        if (!initializeGlobals(s)) {
-            result = -1;
-        } else {
-            s.invoke_vector_test();
-            pRS.finish();
-            waitForMessage();
-        }
-        pRS.destroy();
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UnitTest.java
deleted file mode 100644
index 558a252..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/UnitTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.rs.test_v14;
-import android.content.Context;
-import android.util.Log;
-import android.renderscript.RenderScript.RSMessageHandler;
-
-public class UnitTest extends Thread {
-    public String name;
-    public int result;
-    private ScriptField_ListAllocs_s.Item mItem;
-    private RSTestCore mRSTC;
-    private boolean msgHandled;
-    protected Context mCtx;
-
-    /* These constants must match those in shared.rsh */
-    public static final int RS_MSG_TEST_PASSED = 100;
-    public static final int RS_MSG_TEST_FAILED = 101;
-
-    private static int numTests = 0;
-    public int testID;
-
-    protected UnitTest(RSTestCore rstc, String n, int initResult, Context ctx) {
-        super();
-        mRSTC = rstc;
-        name = n;
-        msgHandled = false;
-        mCtx = ctx;
-        result = initResult;
-        testID = numTests++;
-    }
-
-    protected UnitTest(RSTestCore rstc, String n, Context ctx) {
-        this(rstc, n, 0, ctx);
-    }
-
-    protected UnitTest(RSTestCore rstc, Context ctx) {
-        this (rstc, "<Unknown>", ctx);
-    }
-
-    protected UnitTest(Context ctx) {
-        this (null, ctx);
-    }
-
-    protected void _RS_ASSERT(String message, boolean b) {
-        if(b == false) {
-            result = -1;
-            Log.e(name, message + " FAILED");
-        }
-    }
-
-    protected void updateUI() {
-        if (mItem != null) {
-            mItem.result = result;
-            msgHandled = true;
-            try {
-                mRSTC.refreshTestResults();
-            }
-            catch (IllegalStateException e) {
-                /* Ignore the case where our message receiver has been
-                   disconnected. This happens when we leave the application
-                   before it finishes running all of the unit tests. */
-            }
-        }
-    }
-
-    protected RSMessageHandler mRsMessage = new RSMessageHandler() {
-        public void run() {
-            if (result == 0) {
-                switch (mID) {
-                    case RS_MSG_TEST_PASSED:
-                        result = 1;
-                        break;
-                    case RS_MSG_TEST_FAILED:
-                        result = -1;
-                        break;
-                    default:
-                        RSTest_v14.log("Unit test got unexpected message");
-                        return;
-                }
-            }
-
-            updateUI();
-        }
-    };
-
-    public void waitForMessage() {
-        while (!msgHandled) {
-            yield();
-        }
-    }
-
-    public void setItem(ScriptField_ListAllocs_s.Item item) {
-        mItem = item;
-    }
-
-    public void run() {
-        /* This method needs to be implemented for each subclass */
-        if (mRSTC != null) {
-            mRSTC.refreshTestResults();
-        }
-    }
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/alloc.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/alloc.rs
deleted file mode 100644
index 3116e5a..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/alloc.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "shared.rsh"
-
-int *a;
-int dimX;
-int dimY;
-int dimZ;
-
-rs_allocation aFaces;
-rs_allocation aLOD;
-rs_allocation aFacesLOD;
-
-static bool test_alloc_dims() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            a[i + j * dimX] = i + j * dimX;
-        }
-    }
-
-    rs_allocation alloc = rsGetAllocation(a);
-    _RS_ASSERT(rsAllocationGetDimX(alloc) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(alloc) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(alloc) == dimZ);
-
-    // Test 2D addressing
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(alloc, i, j);
-            int val = *(const int *)p;
-            _RS_ASSERT(val == (i + j * dimX));
-        }
-    }
-
-    // Test 1D addressing
-    for (i = 0; i < dimX * dimY; i++) {
-        rsDebug("Verifying ", i);
-        const void *p = rsGetElementAt(alloc, i);
-        int val = *(const int *)p;
-        _RS_ASSERT(val == i);
-    }
-
-    // Test 3D addressing
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            rsDebug("Verifying ", i + j * dimX);
-            const void *p = rsGetElementAt(alloc, i, j, 0);
-            int val = *(const int *)p;
-            _RS_ASSERT(val == (i + j * dimX));
-        }
-    }
-
-    _RS_ASSERT(rsAllocationGetDimX(aFaces) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aFaces) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aFaces) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aFaces) != 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aFaces) == 0);
-
-    _RS_ASSERT(rsAllocationGetDimX(aLOD) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aLOD) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aLOD) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aLOD) == 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aLOD) != 0);
-
-    _RS_ASSERT(rsAllocationGetDimX(aFacesLOD) == dimX);
-    _RS_ASSERT(rsAllocationGetDimY(aFacesLOD) == dimY);
-    _RS_ASSERT(rsAllocationGetDimZ(aFacesLOD) == dimZ);
-    _RS_ASSERT(rsAllocationGetDimFaces(aFacesLOD) != 0);
-    _RS_ASSERT(rsAllocationGetDimLOD(aFacesLOD) != 0);
-
-    if (failed) {
-        rsDebug("test_alloc_dims FAILED", 0);
-    }
-    else {
-        rsDebug("test_alloc_dims PASSED", 0);
-    }
-
-    return failed;
-}
-
-void alloc_test() {
-    bool failed = false;
-    failed |= test_alloc_dims();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/foreach.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/foreach.rs
deleted file mode 100644
index 3ba3eef..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/foreach.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "shared.rsh"
-
-int *a;
-int dimX;
-int dimY;
-
-void root(int *out, uint32_t x, uint32_t y) {
-    *out = x + y * dimX;
-}
-
-static bool test_foreach_output() {
-    bool failed = false;
-    int i, j;
-
-    for (j = 0; j < dimY; j++) {
-        for (i = 0; i < dimX; i++) {
-            _RS_ASSERT(a[i + j * dimX] == (i + j * dimX));
-        }
-    }
-
-    if (failed) {
-        rsDebug("test_foreach_output FAILED", 0);
-    }
-    else {
-        rsDebug("test_foreach_output PASSED", 0);
-    }
-
-    return failed;
-}
-
-void foreach_test() {
-    bool failed = false;
-    failed |= test_foreach_output();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/fp_mad.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/fp_mad.rs
deleted file mode 100644
index b6f2b2a6..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/fp_mad.rs
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "shared.rsh"
-
-const int TEST_COUNT = 1;
-
-static float data_f1[1025];
-static float4 data_f4[1025];
-
-static void test_mad4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 80); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = (data_f4[i] * 0.02f +
-                          data_f4[i+1] * 0.04f +
-                          data_f4[i+2] * 0.05f +
-                          data_f4[i+3] * 0.1f +
-                          data_f4[i+4] * 0.2f +
-                          data_f4[i+5] * 0.2f +
-                          data_f4[i+6] * 0.1f +
-                          data_f4[i+7] * 0.05f +
-                          data_f4[i+8] * 0.04f +
-                          data_f4[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad4 M ops", 1000.f / time);
-}
-
-static void test_mad(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~1 billion ops
-    for (int ct=0; ct < 1000 * (1000 / 20); ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = (data_f1[i] * 0.02f +
-                          data_f1[i+1] * 0.04f +
-                          data_f1[i+2] * 0.05f +
-                          data_f1[i+3] * 0.1f +
-                          data_f1[i+4] * 0.2f +
-                          data_f1[i+5] * 0.2f +
-                          data_f1[i+6] * 0.1f +
-                          data_f1[i+7] * 0.05f +
-                          data_f1[i+8] * 0.04f +
-                          data_f1[i+9] * 0.02f + 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_mad M ops", 1000.f / time);
-}
-
-static void test_norm(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = normalize(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_norm M ops", 10.f / time);
-}
-
-static void test_sincos4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10 / 4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = sin(data_f4[i]) * cos(data_f4[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos4 M ops", 10.f / time);
-}
-
-static void test_sincos(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~10 M ops
-    for (int ct=0; ct < 1000 * 10; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = sin(data_f1[i]) * cos(data_f1[i]);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_sincos M ops", 10.f / time);
-}
-
-static void test_clamp(uint32_t index) {
-    start();
-
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f1[i] = clamp(data_f1[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp M ops", 100.f / time);
-
-    start();
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100; ct++) {
-        for (int i=0; i < (1000); i++) {
-            if (data_f1[i] < -1.f) data_f1[i] = -1.f;
-            if (data_f1[i] > -1.f) data_f1[i] = 1.f;
-        }
-    }
-
-    time = end(index);
-    rsDebug("fp_clamp ref M ops", 100.f / time);
-}
-
-static void test_clamp4(uint32_t index) {
-    start();
-
-    float total = 0;
-    // Do ~100 M ops
-    for (int ct=0; ct < 1000 * 100 /4; ct++) {
-        for (int i=0; i < (1000); i++) {
-            data_f4[i] = clamp(data_f4[i], -1.f, 1.f);
-        }
-    }
-
-    float time = end(index);
-    rsDebug("fp_clamp4 M ops", 100.f / time);
-}
-
-void fp_mad_test(uint32_t index, int test_num) {
-    int x;
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f;
-        data_f4[x].x = (x & 0xf) * 0.1f;
-        data_f4[x].y = (x & 0xf0) * 0.1f;
-        data_f4[x].z = (x & 0x33) * 0.1f;
-        data_f4[x].w = (x & 0x77) * 0.1f;
-    }
-
-    test_mad4(index);
-    test_mad(index);
-
-    for (x=0; x < 1025; x++) {
-        data_f1[x] = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].x = (x & 0xf) * 0.1f + 1.f;
-        data_f4[x].y = (x & 0xf0) * 0.1f + 1.f;
-        data_f4[x].z = (x & 0x33) * 0.1f + 1.f;
-        data_f4[x].w = (x & 0x77) * 0.1f + 1.f;
-    }
-
-    test_norm(index);
-    test_sincos4(index);
-    test_sincos(index);
-    test_clamp4(index);
-    test_clamp(index);
-
-    // TODO Actually verify test result accuracy
-    rsDebug("fp_mad_test PASSED", 0);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs
deleted file mode 100644
index e6b37f6..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs
+++ /dev/null
@@ -1,462 +0,0 @@
-#include "shared.rsh"
-
-// Testing math library
-
-volatile float f1;
-volatile float2 f2;
-volatile float3 f3;
-volatile float4 f4;
-
-volatile int i1;
-volatile int2 i2;
-volatile int3 i3;
-volatile int4 i4;
-
-volatile uint ui1;
-volatile uint2 ui2;
-volatile uint3 ui3;
-volatile uint4 ui4;
-
-volatile short s1;
-volatile short2 s2;
-volatile short3 s3;
-volatile short4 s4;
-
-volatile ushort us1;
-volatile ushort2 us2;
-volatile ushort3 us3;
-volatile ushort4 us4;
-
-volatile char c1;
-volatile char2 c2;
-volatile char3 c3;
-volatile char4 c4;
-
-volatile uchar uc1;
-volatile uchar2 uc2;
-volatile uchar3 uc3;
-volatile uchar4 uc4;
-
-#define DECL_INT(prefix)            \
-volatile char prefix##_c_1 = 1;     \
-volatile char2 prefix##_c_2 = 1;    \
-volatile char3 prefix##_c_3 = 1;    \
-volatile char4 prefix##_c_4 = 1;    \
-volatile uchar prefix##_uc_1 = 1;   \
-volatile uchar2 prefix##_uc_2 = 1;  \
-volatile uchar3 prefix##_uc_3 = 1;  \
-volatile uchar4 prefix##_uc_4 = 1;  \
-volatile short prefix##_s_1 = 1;    \
-volatile short2 prefix##_s_2 = 1;   \
-volatile short3 prefix##_s_3 = 1;   \
-volatile short4 prefix##_s_4 = 1;   \
-volatile ushort prefix##_us_1 = 1;  \
-volatile ushort2 prefix##_us_2 = 1; \
-volatile ushort3 prefix##_us_3 = 1; \
-volatile ushort4 prefix##_us_4 = 1; \
-volatile int prefix##_i_1 = 1;      \
-volatile int2 prefix##_i_2 = 1;     \
-volatile int3 prefix##_i_3 = 1;     \
-volatile int4 prefix##_i_4 = 1;     \
-volatile uint prefix##_ui_1 = 1;    \
-volatile uint2 prefix##_ui_2 = 1;   \
-volatile uint3 prefix##_ui_3 = 1;   \
-volatile uint4 prefix##_ui_4 = 1;   \
-volatile long prefix##_l_1 = 1;     \
-volatile ulong prefix##_ul_1 = 1;
-
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
-
-#define TEST_INT_OP_TYPE(op, type)                      \
-rsDebug("Testing " #op " for " #type "1", i++);         \
-res_##type##_1 = src1_##type##_1 op src2_##type##_1;    \
-rsDebug("Testing " #op " for " #type "2", i++);         \
-res_##type##_2 = src1_##type##_2 op src2_##type##_2;    \
-rsDebug("Testing " #op " for " #type "3", i++);         \
-res_##type##_3 = src1_##type##_3 op src2_##type##_3;    \
-rsDebug("Testing " #op " for " #type "4", i++);         \
-res_##type##_4 = src1_##type##_4 op src2_##type##_4;
-
-#define TEST_INT_OP(op)                     \
-TEST_INT_OP_TYPE(op, c)                     \
-TEST_INT_OP_TYPE(op, uc)                    \
-TEST_INT_OP_TYPE(op, s)                     \
-TEST_INT_OP_TYPE(op, us)                    \
-TEST_INT_OP_TYPE(op, i)                     \
-TEST_INT_OP_TYPE(op, ui)                    \
-rsDebug("Testing " #op " for l1", i++);     \
-res_l_1 = src1_l_1 op src2_l_1;             \
-rsDebug("Testing " #op " for ul1", i++);    \
-res_ul_1 = src1_ul_1 op src2_ul_1;
-
-#define TEST_XN_FUNC_YN(typeout, fnc, typein)   \
-    res_##typeout##_1 = fnc(src1_##typein##_1); \
-    res_##typeout##_2 = fnc(src1_##typein##_2); \
-    res_##typeout##_3 = fnc(src1_##typein##_3); \
-    res_##typeout##_4 = fnc(src1_##typein##_4);
-
-#define TEST_XN_FUNC_XN_XN(type, fnc)                       \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1); \
-    res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2); \
-    res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3); \
-    res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4);
-
-#define TEST_X_FUNC_X_X_X(type, fnc)    \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src2_##type##_1);
-
-#define TEST_IN_FUNC_IN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, uc)    \
-    TEST_XN_FUNC_YN(c, fnc, c)      \
-    TEST_XN_FUNC_YN(us, fnc, us)    \
-    TEST_XN_FUNC_YN(s, fnc, s)      \
-    TEST_XN_FUNC_YN(ui, fnc, ui)    \
-    TEST_XN_FUNC_YN(i, fnc, i)
-
-#define TEST_UIN_FUNC_IN(fnc)       \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, c)     \
-    TEST_XN_FUNC_YN(us, fnc, s)     \
-    TEST_XN_FUNC_YN(ui, fnc, i)     \
-
-#define TEST_IN_FUNC_IN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_XN_XN(uc, fnc)     \
-    TEST_XN_FUNC_XN_XN(c, fnc)      \
-    TEST_XN_FUNC_XN_XN(us, fnc)     \
-    TEST_XN_FUNC_XN_XN(s, fnc)      \
-    TEST_XN_FUNC_XN_XN(ui, fnc)     \
-    TEST_XN_FUNC_XN_XN(i, fnc)
-
-#define TEST_I_FUNC_I_I_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_X_FUNC_X_X_X(uc, fnc)      \
-    TEST_X_FUNC_X_X_X(c, fnc)       \
-    TEST_X_FUNC_X_X_X(us, fnc)      \
-    TEST_X_FUNC_X_X_X(s, fnc)       \
-    TEST_X_FUNC_X_X_X(ui, fnc)      \
-    TEST_X_FUNC_X_X_X(i, fnc)
-
-#define TEST_FN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f2 = fnc(f2);                   \
-    f3 = fnc(f3);                   \
-    f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (float*) &f1);     \
-    f2 = fnc(f2, (float2*) &f2);    \
-    f3 = fnc(f3, (float3*) &f3);    \
-    f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f2);               \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_F34_FUNC_F34_F34(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f1);               \
-    f3 = fnc(f3, f1);               \
-    f4 = fnc(f4, f1);
-
-#define TEST_F_FUNC_FN(fnc)         \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f1 = fnc(f2);                   \
-    f1 = fnc(f3);                   \
-    f1 = fnc(f4);
-
-#define TEST_F_FUNC_FN_FN(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f1 = fnc(f2, f2);               \
-    f1 = fnc(f3, f3);               \
-    f1 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i2);               \
-    f3 = fnc(f3, i3);               \
-    f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i1);               \
-    f3 = fnc(f3, i1);               \
-    f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f2, f2);           \
-    f3 = fnc(f3, f3, f3);           \
-    f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_FN_F(fnc)   \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f1, f1);           \
-    f3 = fnc(f3, f1, f1);           \
-    f4 = fnc(f4, f1, f1);
-
-#define TEST_FN_FUNC_FN_PIN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (int*) &i1);       \
-    f2 = fnc(f2, (int2*) &i2);      \
-    f3 = fnc(f3, (int3*) &i3);      \
-    f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, (int*) &i1);   \
-    f2 = fnc(f2, f2, (int2*) &i2);  \
-    f3 = fnc(f3, f3, (int3*) &i3);  \
-    f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    i1 = fnc(f1);                   \
-    i2 = fnc(f2);                   \
-    i3 = fnc(f3);                   \
-    i4 = fnc(f4);
-
-static bool test_fp_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_FN_FUNC_FN(acos);
-    TEST_FN_FUNC_FN(acosh);
-    TEST_FN_FUNC_FN(acospi);
-    TEST_FN_FUNC_FN(asin);
-    TEST_FN_FUNC_FN(asinh);
-    TEST_FN_FUNC_FN(asinpi);
-    TEST_FN_FUNC_FN(atan);
-    TEST_FN_FUNC_FN_FN(atan2);
-    TEST_FN_FUNC_FN(atanh);
-    TEST_FN_FUNC_FN(atanpi);
-    TEST_FN_FUNC_FN_FN(atan2pi);
-    TEST_FN_FUNC_FN(cbrt);
-    TEST_FN_FUNC_FN(ceil);
-    TEST_FN_FUNC_FN_FN_FN(clamp);
-    TEST_FN_FUNC_FN_FN_F(clamp);
-    TEST_FN_FUNC_FN_FN(copysign);
-    TEST_FN_FUNC_FN(cos);
-    TEST_FN_FUNC_FN(cosh);
-    TEST_FN_FUNC_FN(cospi);
-    TEST_F34_FUNC_F34_F34(cross);
-    TEST_FN_FUNC_FN(degrees);
-    TEST_F_FUNC_FN_FN(distance);
-    TEST_F_FUNC_FN_FN(dot);
-    TEST_FN_FUNC_FN(erfc);
-    TEST_FN_FUNC_FN(erf);
-    TEST_FN_FUNC_FN(exp);
-    TEST_FN_FUNC_FN(exp2);
-    TEST_FN_FUNC_FN(exp10);
-    TEST_FN_FUNC_FN(expm1);
-    TEST_FN_FUNC_FN(fabs);
-    TEST_FN_FUNC_FN_FN(fdim);
-    TEST_FN_FUNC_FN(floor);
-    TEST_FN_FUNC_FN_FN_FN(fma);
-    TEST_FN_FUNC_FN_FN(fmax);
-    TEST_FN_FUNC_FN_F(fmax);
-    TEST_FN_FUNC_FN_FN(fmin);
-    TEST_FN_FUNC_FN_F(fmin);
-    TEST_FN_FUNC_FN_FN(fmod);
-    TEST_FN_FUNC_FN_PFN(fract);
-    TEST_FN_FUNC_FN_PIN(frexp);
-    TEST_FN_FUNC_FN_FN(hypot);
-    TEST_IN_FUNC_FN(ilogb);
-    TEST_FN_FUNC_FN_IN(ldexp);
-    TEST_FN_FUNC_FN_I(ldexp);
-    TEST_F_FUNC_FN(length);
-    TEST_FN_FUNC_FN(lgamma);
-    TEST_FN_FUNC_FN_PIN(lgamma);
-    TEST_FN_FUNC_FN(log);
-    TEST_FN_FUNC_FN(log2);
-    TEST_FN_FUNC_FN(log10);
-    TEST_FN_FUNC_FN(log1p);
-    TEST_FN_FUNC_FN(logb);
-    TEST_FN_FUNC_FN_FN_FN(mad);
-    TEST_FN_FUNC_FN_FN(max);
-    TEST_FN_FUNC_FN_F(max);
-    TEST_FN_FUNC_FN_FN(min);
-    TEST_FN_FUNC_FN_F(min);
-    TEST_FN_FUNC_FN_FN_FN(mix);
-    TEST_FN_FUNC_FN_FN_F(mix);
-    TEST_FN_FUNC_FN_PFN(modf);
-    // nan
-    TEST_FN_FUNC_FN_FN(nextafter);
-    TEST_FN_FUNC_FN(normalize);
-    TEST_FN_FUNC_FN_FN(pow);
-    TEST_FN_FUNC_FN_IN(pown);
-    TEST_FN_FUNC_FN_FN(powr);
-    TEST_FN_FUNC_FN(radians);
-    TEST_FN_FUNC_FN_FN(remainder);
-    TEST_FN_FUNC_FN_FN_PIN(remquo);
-    TEST_FN_FUNC_FN(rint);
-    TEST_FN_FUNC_FN_IN(rootn);
-    TEST_FN_FUNC_FN(round);
-    TEST_FN_FUNC_FN(rsqrt);
-    TEST_FN_FUNC_FN(sign);
-    TEST_FN_FUNC_FN(sin);
-    TEST_FN_FUNC_FN_PFN(sincos);
-    TEST_FN_FUNC_FN(sinh);
-    TEST_FN_FUNC_FN(sinpi);
-    TEST_FN_FUNC_FN(sqrt);
-    TEST_FN_FUNC_FN_FN(step);
-    TEST_FN_FUNC_FN_F(step);
-    TEST_FN_FUNC_FN(tan);
-    TEST_FN_FUNC_FN(tanh);
-    TEST_FN_FUNC_FN(tanpi);
-    TEST_FN_FUNC_FN(tgamma);
-    TEST_FN_FUNC_FN(trunc);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_fp_math FAILED", time);
-    }
-    else {
-        rsDebug("test_fp_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_int_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_UIN_FUNC_IN(abs);
-    TEST_IN_FUNC_IN(clz);
-    TEST_IN_FUNC_IN_IN(min);
-    TEST_IN_FUNC_IN_IN(max);
-    TEST_I_FUNC_I_I_I(rsClamp);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_int_math FAILED", time);
-    }
-    else {
-        rsDebug("test_int_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_basic_operators() {
-    bool failed = false;
-    int i = 0;
-
-    TEST_INT_OP(+);
-    TEST_INT_OP(-);
-    TEST_INT_OP(*);
-    TEST_INT_OP(/);
-    TEST_INT_OP(%);
-    TEST_INT_OP(<<);
-    TEST_INT_OP(>>);
-
-    if (failed) {
-        rsDebug("test_basic_operators FAILED", 0);
-    }
-    else {
-        rsDebug("test_basic_operators PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define TEST_CVT(to, from, type)                        \
-rsDebug("Testing convert from " #from " to " #to, 0);   \
-to##1 = from##1;                                        \
-to##2 = convert_##type##2(from##2);                     \
-to##3 = convert_##type##3(from##3);                     \
-to##4 = convert_##type##4(from##4);
-
-#define TEST_CVT_MATRIX(to, type)   \
-TEST_CVT(to, c, type);              \
-TEST_CVT(to, uc, type);             \
-TEST_CVT(to, s, type);              \
-TEST_CVT(to, us, type);             \
-TEST_CVT(to, i, type);              \
-TEST_CVT(to, ui, type);             \
-TEST_CVT(to, f, type);              \
-
-static bool test_convert() {
-    bool failed = false;
-
-    TEST_CVT_MATRIX(c, char);
-    TEST_CVT_MATRIX(uc, uchar);
-    TEST_CVT_MATRIX(s, short);
-    TEST_CVT_MATRIX(us, ushort);
-    TEST_CVT_MATRIX(i, int);
-    TEST_CVT_MATRIX(ui, uint);
-    TEST_CVT_MATRIX(f, float);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define INIT_PREFIX_TYPE(prefix, type)  \
-prefix##_##type##_1 = 1;                \
-prefix##_##type##_2.x = 1;              \
-prefix##_##type##_2.y = 1;              \
-prefix##_##type##_3.x = 1;              \
-prefix##_##type##_3.y = 1;              \
-prefix##_##type##_3.z = 1;              \
-prefix##_##type##_4.x = 1;              \
-prefix##_##type##_4.y = 1;              \
-prefix##_##type##_4.z = 1;              \
-prefix##_##type##_4.w = 1;
-
-#define INIT_TYPE(type)         \
-INIT_PREFIX_TYPE(src1, type)    \
-INIT_PREFIX_TYPE(src2, type)    \
-INIT_PREFIX_TYPE(res, type)
-
-#define INIT_ALL    \
-INIT_TYPE(c);       \
-INIT_TYPE(uc);      \
-INIT_TYPE(s);       \
-INIT_TYPE(us);      \
-INIT_TYPE(i);       \
-INIT_TYPE(ui);
-
-void math_test(uint32_t index, int test_num) {
-    bool failed = false;
-    INIT_ALL;
-    failed |= test_convert();
-    failed |= test_fp_math(index);
-    failed |= test_int_math(index);
-    failed |= test_basic_operators();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs.bak b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs.bak
deleted file mode 100644
index ad802ca..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs.bak
+++ /dev/null
@@ -1,423 +0,0 @@
-#include "shared.rsh"
-
-// Testing math library
-
-volatile float f1;
-volatile float2 f2;
-volatile float3 f3;
-volatile float4 f4;
-
-volatile int i1;
-volatile int2 i2;
-volatile int3 i3;
-volatile int4 i4;
-
-volatile uint ui1;
-volatile uint2 ui2;
-volatile uint3 ui3;
-volatile uint4 ui4;
-
-volatile short s1;
-volatile short2 s2;
-volatile short3 s3;
-volatile short4 s4;
-
-volatile ushort us1;
-volatile ushort2 us2;
-volatile ushort3 us3;
-volatile ushort4 us4;
-
-volatile char c1;
-volatile char2 c2;
-volatile char3 c3;
-volatile char4 c4;
-
-volatile uchar uc1;
-volatile uchar2 uc2;
-volatile uchar3 uc3;
-volatile uchar4 uc4;
-
-#define DECL_INT(prefix)            \
-volatile char prefix##_c_1 = 1;     \
-volatile char2 prefix##_c_2 = 1;    \
-volatile char3 prefix##_c_3 = 1;    \
-volatile char4 prefix##_c_4 = 1;    \
-volatile uchar prefix##_uc_1 = 1;   \
-volatile uchar2 prefix##_uc_2 = 1;  \
-volatile uchar3 prefix##_uc_3 = 1;  \
-volatile uchar4 prefix##_uc_4 = 1;  \
-volatile short prefix##_s_1 = 1;    \
-volatile short2 prefix##_s_2 = 1;   \
-volatile short3 prefix##_s_3 = 1;   \
-volatile short4 prefix##_s_4 = 1;   \
-volatile ushort prefix##_us_1 = 1;  \
-volatile ushort2 prefix##_us_2 = 1; \
-volatile ushort3 prefix##_us_3 = 1; \
-volatile ushort4 prefix##_us_4 = 1; \
-volatile int prefix##_i_1 = 1;      \
-volatile int2 prefix##_i_2 = 1;     \
-volatile int3 prefix##_i_3 = 1;     \
-volatile int4 prefix##_i_4 = 1;     \
-volatile uint prefix##_ui_1 = 1;    \
-volatile uint2 prefix##_ui_2 = 1;   \
-volatile uint3 prefix##_ui_3 = 1;   \
-volatile uint4 prefix##_ui_4 = 1;   \
-volatile long prefix##_l_1 = 1;     \
-volatile ulong prefix##_ul_1 = 1;
-
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
-
-#define TEST_INT_OP_TYPE(op, type)                      \
-rsDebug("Testing " #op " for " #type "3", i++);         \
-res_##type##_3 = src1_##type##_3 op src2_##type##_3;    \
-
-#define TEST_INT_OP(op)                     \
-TEST_INT_OP_TYPE(op, c)                     \
-TEST_INT_OP_TYPE(op, uc)                    \
-
-#define TEST_XN_FUNC_YN(typeout, fnc, typein)   \
-    res_##typeout##_1 = fnc(src1_##typein##_1); \
-    res_##typeout##_2 = fnc(src1_##typein##_2); \
-    res_##typeout##_3 = fnc(src1_##typein##_3); \
-    res_##typeout##_4 = fnc(src1_##typein##_4);
-
-#define TEST_XN_FUNC_XN_XN(type, fnc)                       \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1); \
-    res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2); \
-    res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3); \
-    res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4);
-
-#define TEST_X_FUNC_X_X_X(type, fnc)    \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src2_##type##_1);
-
-#define TEST_IN_FUNC_IN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, uc)    \
-    TEST_XN_FUNC_YN(c, fnc, c)      \
-    TEST_XN_FUNC_YN(us, fnc, us)    \
-    TEST_XN_FUNC_YN(s, fnc, s)      \
-    TEST_XN_FUNC_YN(ui, fnc, ui)    \
-    TEST_XN_FUNC_YN(i, fnc, i)
-
-#define TEST_UIN_FUNC_IN(fnc)       \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, c)     \
-    TEST_XN_FUNC_YN(us, fnc, s)     \
-    TEST_XN_FUNC_YN(ui, fnc, i)     \
-
-#define TEST_IN_FUNC_IN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_XN_XN(uc, fnc)     \
-    TEST_XN_FUNC_XN_XN(c, fnc)      \
-    TEST_XN_FUNC_XN_XN(us, fnc)     \
-    TEST_XN_FUNC_XN_XN(s, fnc)      \
-    TEST_XN_FUNC_XN_XN(ui, fnc)     \
-    TEST_XN_FUNC_XN_XN(i, fnc)
-
-#define TEST_I_FUNC_I_I_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_X_FUNC_X_X_X(uc, fnc)      \
-    TEST_X_FUNC_X_X_X(c, fnc)       \
-    TEST_X_FUNC_X_X_X(us, fnc)      \
-    TEST_X_FUNC_X_X_X(s, fnc)       \
-    TEST_X_FUNC_X_X_X(ui, fnc)      \
-    TEST_X_FUNC_X_X_X(i, fnc)
-
-#define TEST_FN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f2 = fnc(f2);                   \
-    f3 = fnc(f3);                   \
-    f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (float*) &f1);     \
-    f2 = fnc(f2, (float2*) &f2);    \
-    f3 = fnc(f3, (float3*) &f3);    \
-    f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f2);               \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_F34_FUNC_F34_F34(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f1);               \
-    f3 = fnc(f3, f1);               \
-    f4 = fnc(f4, f1);
-
-#define TEST_F_FUNC_FN(fnc)         \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f1 = fnc(f2);                   \
-    f1 = fnc(f3);                   \
-    f1 = fnc(f4);
-
-#define TEST_F_FUNC_FN_FN(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f1 = fnc(f2, f2);               \
-    f1 = fnc(f3, f3);               \
-    f1 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i2);               \
-    f3 = fnc(f3, i3);               \
-    f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i1);               \
-    f3 = fnc(f3, i1);               \
-    f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f2, f2);           \
-    f3 = fnc(f3, f3, f3);           \
-    f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_FN_F(fnc)   \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f1, f1);           \
-    f3 = fnc(f3, f1, f1);           \
-    f4 = fnc(f4, f1, f1);
-
-#define TEST_FN_FUNC_FN_PIN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (int*) &i1);       \
-    f2 = fnc(f2, (int2*) &i2);      \
-    f3 = fnc(f3, (int3*) &i3);      \
-    f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, (int*) &i1);   \
-    f2 = fnc(f2, f2, (int2*) &i2);  \
-    f3 = fnc(f3, f3, (int3*) &i3);  \
-    f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    i1 = fnc(f1);                   \
-    i2 = fnc(f2);                   \
-    i3 = fnc(f3);                   \
-    i4 = fnc(f4);
-
-static bool test_fp_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_FN_FUNC_FN(acos);
-    TEST_FN_FUNC_FN(acosh);
-    TEST_FN_FUNC_FN(acospi);
-    TEST_FN_FUNC_FN(asin);
-    TEST_FN_FUNC_FN(asinh);
-    TEST_FN_FUNC_FN(asinpi);
-    TEST_FN_FUNC_FN(atan);
-    TEST_FN_FUNC_FN_FN(atan2);
-    TEST_FN_FUNC_FN(atanh);
-    TEST_FN_FUNC_FN(atanpi);
-    TEST_FN_FUNC_FN_FN(atan2pi);
-    TEST_FN_FUNC_FN(cbrt);
-    TEST_FN_FUNC_FN(ceil);
-    TEST_FN_FUNC_FN_FN_FN(clamp);
-    TEST_FN_FUNC_FN_FN_F(clamp);
-    TEST_FN_FUNC_FN_FN(copysign);
-    TEST_FN_FUNC_FN(cos);
-    TEST_FN_FUNC_FN(cosh);
-    TEST_FN_FUNC_FN(cospi);
-    TEST_F34_FUNC_F34_F34(cross);
-    TEST_FN_FUNC_FN(degrees);
-    TEST_F_FUNC_FN_FN(distance);
-    TEST_F_FUNC_FN_FN(dot);
-    TEST_FN_FUNC_FN(erfc);
-    TEST_FN_FUNC_FN(erf);
-    TEST_FN_FUNC_FN(exp);
-    TEST_FN_FUNC_FN(exp2);
-    TEST_FN_FUNC_FN(exp10);
-    TEST_FN_FUNC_FN(expm1);
-    TEST_FN_FUNC_FN(fabs);
-    TEST_FN_FUNC_FN_FN(fdim);
-    TEST_FN_FUNC_FN(floor);
-    TEST_FN_FUNC_FN_FN_FN(fma);
-    TEST_FN_FUNC_FN_FN(fmax);
-    TEST_FN_FUNC_FN_F(fmax);
-    TEST_FN_FUNC_FN_FN(fmin);
-    TEST_FN_FUNC_FN_F(fmin);
-    TEST_FN_FUNC_FN_FN(fmod);
-    TEST_FN_FUNC_FN_PFN(fract);
-    TEST_FN_FUNC_FN_PIN(frexp);
-    TEST_FN_FUNC_FN_FN(hypot);
-    TEST_IN_FUNC_FN(ilogb);
-    TEST_FN_FUNC_FN_IN(ldexp);
-    TEST_FN_FUNC_FN_I(ldexp);
-    TEST_F_FUNC_FN(length);
-    TEST_FN_FUNC_FN(lgamma);
-    TEST_FN_FUNC_FN_PIN(lgamma);
-    TEST_FN_FUNC_FN(log);
-    TEST_FN_FUNC_FN(log2);
-    TEST_FN_FUNC_FN(log10);
-    TEST_FN_FUNC_FN(log1p);
-    TEST_FN_FUNC_FN(logb);
-    TEST_FN_FUNC_FN_FN_FN(mad);
-    TEST_FN_FUNC_FN_FN(max);
-    TEST_FN_FUNC_FN_F(max);
-    TEST_FN_FUNC_FN_FN(min);
-    TEST_FN_FUNC_FN_F(min);
-    TEST_FN_FUNC_FN_FN_FN(mix);
-    TEST_FN_FUNC_FN_FN_F(mix);
-    TEST_FN_FUNC_FN_PFN(modf);
-    // nan
-    TEST_FN_FUNC_FN_FN(nextafter);
-    TEST_FN_FUNC_FN(normalize);
-    TEST_FN_FUNC_FN_FN(pow);
-    TEST_FN_FUNC_FN_IN(pown);
-    TEST_FN_FUNC_FN_FN(powr);
-    TEST_FN_FUNC_FN(radians);
-    TEST_FN_FUNC_FN_FN(remainder);
-    TEST_FN_FUNC_FN_FN_PIN(remquo);
-    TEST_FN_FUNC_FN(rint);
-    TEST_FN_FUNC_FN_IN(rootn);
-    TEST_FN_FUNC_FN(round);
-    TEST_FN_FUNC_FN(rsqrt);
-    TEST_FN_FUNC_FN(sign);
-    TEST_FN_FUNC_FN(sin);
-    TEST_FN_FUNC_FN_PFN(sincos);
-    TEST_FN_FUNC_FN(sinh);
-    TEST_FN_FUNC_FN(sinpi);
-    TEST_FN_FUNC_FN(sqrt);
-    TEST_FN_FUNC_FN_FN(step);
-    TEST_FN_FUNC_FN_F(step);
-    TEST_FN_FUNC_FN(tan);
-    TEST_FN_FUNC_FN(tanh);
-    TEST_FN_FUNC_FN(tanpi);
-    TEST_FN_FUNC_FN(tgamma);
-    TEST_FN_FUNC_FN(trunc);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_fp_math FAILED", time);
-    }
-    else {
-        rsDebug("test_fp_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_int_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_UIN_FUNC_IN(abs);
-    TEST_IN_FUNC_IN(clz);
-    TEST_IN_FUNC_IN_IN(min);
-    TEST_IN_FUNC_IN_IN(max);
-    TEST_I_FUNC_I_I_I(rsClamp);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_int_math FAILED", time);
-    }
-    else {
-        rsDebug("test_int_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_basic_operators() {
-    bool failed = false;
-    int i = 0;
-
-    TEST_INT_OP(+);
-    TEST_INT_OP(-);
-    TEST_INT_OP(*);
-    TEST_INT_OP(/);
-    TEST_INT_OP(%);
-    TEST_INT_OP(<<);
-    TEST_INT_OP(>>);
-
-    if (failed) {
-        rsDebug("test_basic_operators FAILED", 0);
-    }
-    else {
-        rsDebug("test_basic_operators PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define TEST_CVT(to, from, type)                        \
-rsDebug("Testing convert from " #from " to " #to, 0);   \
-to##1 = from##1;                                        \
-to##2 = convert_##type##2(from##2);                     \
-to##3 = convert_##type##3(from##3);                     \
-to##4 = convert_##type##4(from##4);
-
-#define TEST_CVT_MATRIX(to, type)   \
-TEST_CVT(to, c, type);              \
-TEST_CVT(to, uc, type);             \
-TEST_CVT(to, s, type);              \
-TEST_CVT(to, us, type);             \
-TEST_CVT(to, i, type);              \
-TEST_CVT(to, ui, type);             \
-TEST_CVT(to, f, type);              \
-
-static bool test_convert() {
-    bool failed = false;
-
-    TEST_CVT_MATRIX(c, char);
-    TEST_CVT_MATRIX(uc, uchar);
-    TEST_CVT_MATRIX(s, short);
-    TEST_CVT_MATRIX(us, ushort);
-    TEST_CVT_MATRIX(i, int);
-    TEST_CVT_MATRIX(ui, uint);
-    TEST_CVT_MATRIX(f, float);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_test(uint32_t index, int test_num) {
-    bool failed = false;
-    rsDebug("Here ", 1);
-    res_uc_3 = src1_uc_3 / src2_uc_3;
-    rsDebug("Here ", 2);
-    failed |= test_basic_operators();
-    rsDebug("Here ", 3);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs.orig b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs.orig
deleted file mode 100644
index aae29a4..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/math.rs.orig
+++ /dev/null
@@ -1,436 +0,0 @@
-#include "shared.rsh"
-
-// Testing math library
-
-volatile float f1;
-volatile float2 f2;
-volatile float3 f3;
-volatile float4 f4;
-
-volatile int i1;
-volatile int2 i2;
-volatile int3 i3;
-volatile int4 i4;
-
-volatile uint ui1;
-volatile uint2 ui2;
-volatile uint3 ui3;
-volatile uint4 ui4;
-
-volatile short s1;
-volatile short2 s2;
-volatile short3 s3;
-volatile short4 s4;
-
-volatile ushort us1;
-volatile ushort2 us2;
-volatile ushort3 us3;
-volatile ushort4 us4;
-
-volatile char c1;
-volatile char2 c2;
-volatile char3 c3;
-volatile char4 c4;
-
-volatile uchar uc1;
-volatile uchar2 uc2;
-volatile uchar3 uc3;
-volatile uchar4 uc4;
-
-#define DECL_INT(prefix)            \
-volatile char prefix##_c_1 = 1;     \
-volatile char2 prefix##_c_2 = 1;    \
-volatile char3 prefix##_c_3 = 1;    \
-volatile char4 prefix##_c_4 = 1;    \
-volatile uchar prefix##_uc_1 = 1;   \
-volatile uchar2 prefix##_uc_2 = 1;  \
-volatile uchar3 prefix##_uc_3 = 1;  \
-volatile uchar4 prefix##_uc_4 = 1;  \
-volatile short prefix##_s_1 = 1;    \
-volatile short2 prefix##_s_2 = 1;   \
-volatile short3 prefix##_s_3 = 1;   \
-volatile short4 prefix##_s_4 = 1;   \
-volatile ushort prefix##_us_1 = 1;  \
-volatile ushort2 prefix##_us_2 = 1; \
-volatile ushort3 prefix##_us_3 = 1; \
-volatile ushort4 prefix##_us_4 = 1; \
-volatile int prefix##_i_1 = 1;      \
-volatile int2 prefix##_i_2 = 1;     \
-volatile int3 prefix##_i_3 = 1;     \
-volatile int4 prefix##_i_4 = 1;     \
-volatile uint prefix##_ui_1 = 1;    \
-volatile uint2 prefix##_ui_2 = 1;   \
-volatile uint3 prefix##_ui_3 = 1;   \
-volatile uint4 prefix##_ui_4 = 1;   \
-volatile long prefix##_l_1 = 1;     \
-volatile ulong prefix##_ul_1 = 1;
-
-DECL_INT(res)
-DECL_INT(src1)
-DECL_INT(src2)
-
-#define TEST_INT_OP_TYPE(op, type)                      \
-rsDebug("Testing " #op " for " #type "1", i++);         \
-res_##type##_1 = src1_##type##_1 op src2_##type##_1;    \
-rsDebug("Testing " #op " for " #type "2", i++);         \
-res_##type##_2 = src1_##type##_2 op src2_##type##_2;    \
-rsDebug("Testing " #op " for " #type "3", i++);         \
-res_##type##_3 = src1_##type##_3 op src2_##type##_3;    \
-rsDebug("Testing " #op " for " #type "4", i++);         \
-res_##type##_4 = src1_##type##_4 op src2_##type##_4;
-
-#define TEST_INT_OP(op)                     \
-TEST_INT_OP_TYPE(op, c)                     \
-TEST_INT_OP_TYPE(op, uc)                    \
-TEST_INT_OP_TYPE(op, s)                     \
-TEST_INT_OP_TYPE(op, us)                    \
-TEST_INT_OP_TYPE(op, i)                     \
-TEST_INT_OP_TYPE(op, ui)                    \
-rsDebug("Testing " #op " for l1", i++);     \
-res_l_1 = src1_l_1 op src2_l_1;             \
-rsDebug("Testing " #op " for ul1", i++);    \
-res_ul_1 = src1_ul_1 op src2_ul_1;
-
-#define TEST_XN_FUNC_YN(typeout, fnc, typein)   \
-    res_##typeout##_1 = fnc(src1_##typein##_1); \
-    res_##typeout##_2 = fnc(src1_##typein##_2); \
-    res_##typeout##_3 = fnc(src1_##typein##_3); \
-    res_##typeout##_4 = fnc(src1_##typein##_4);
-
-#define TEST_XN_FUNC_XN_XN(type, fnc)                       \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1); \
-    res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2); \
-    res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3); \
-    res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4);
-
-#define TEST_X_FUNC_X_X_X(type, fnc)    \
-    res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src2_##type##_1);
-
-#define TEST_IN_FUNC_IN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, uc)    \
-    TEST_XN_FUNC_YN(c, fnc, c)      \
-    TEST_XN_FUNC_YN(us, fnc, us)    \
-    TEST_XN_FUNC_YN(s, fnc, s)      \
-    TEST_XN_FUNC_YN(ui, fnc, ui)    \
-    TEST_XN_FUNC_YN(i, fnc, i)
-
-#define TEST_UIN_FUNC_IN(fnc)       \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_YN(uc, fnc, c)     \
-    TEST_XN_FUNC_YN(us, fnc, s)     \
-    TEST_XN_FUNC_YN(ui, fnc, i)     \
-
-#define TEST_IN_FUNC_IN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_XN_FUNC_XN_XN(uc, fnc)     \
-    TEST_XN_FUNC_XN_XN(c, fnc)      \
-    TEST_XN_FUNC_XN_XN(us, fnc)     \
-    TEST_XN_FUNC_XN_XN(s, fnc)      \
-    TEST_XN_FUNC_XN_XN(ui, fnc)     \
-    TEST_XN_FUNC_XN_XN(i, fnc)
-
-#define TEST_I_FUNC_I_I_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    TEST_X_FUNC_X_X_X(uc, fnc)      \
-    TEST_X_FUNC_X_X_X(c, fnc)       \
-    TEST_X_FUNC_X_X_X(us, fnc)      \
-    TEST_X_FUNC_X_X_X(s, fnc)       \
-    TEST_X_FUNC_X_X_X(ui, fnc)      \
-    TEST_X_FUNC_X_X_X(i, fnc)
-
-#define TEST_FN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f2 = fnc(f2);                   \
-    f3 = fnc(f3);                   \
-    f4 = fnc(f4);
-
-#define TEST_FN_FUNC_FN_PFN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (float*) &f1);     \
-    f2 = fnc(f2, (float2*) &f2);    \
-    f3 = fnc(f3, (float3*) &f3);    \
-    f4 = fnc(f4, (float4*) &f4);
-
-#define TEST_FN_FUNC_FN_FN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f2);               \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_F34_FUNC_F34_F34(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f3 = fnc(f3, f3);               \
-    f4 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_F(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f2 = fnc(f2, f1);               \
-    f3 = fnc(f3, f1);               \
-    f4 = fnc(f4, f1);
-
-#define TEST_F_FUNC_FN(fnc)         \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1);                   \
-    f1 = fnc(f2);                   \
-    f1 = fnc(f3);                   \
-    f1 = fnc(f4);
-
-#define TEST_F_FUNC_FN_FN(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1);               \
-    f1 = fnc(f2, f2);               \
-    f1 = fnc(f3, f3);               \
-    f1 = fnc(f4, f4);
-
-#define TEST_FN_FUNC_FN_IN(fnc)     \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i2);               \
-    f3 = fnc(f3, i3);               \
-    f4 = fnc(f4, i4);
-
-#define TEST_FN_FUNC_FN_I(fnc)      \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, i1);               \
-    f2 = fnc(f2, i1);               \
-    f3 = fnc(f3, i1);               \
-    f4 = fnc(f4, i1);
-
-#define TEST_FN_FUNC_FN_FN_FN(fnc)  \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f2, f2);           \
-    f3 = fnc(f3, f3, f3);           \
-    f4 = fnc(f4, f4, f4);
-
-#define TEST_FN_FUNC_FN_FN_F(fnc)   \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, f1);           \
-    f2 = fnc(f2, f1, f1);           \
-    f3 = fnc(f3, f1, f1);           \
-    f4 = fnc(f4, f1, f1);
-
-#define TEST_FN_FUNC_FN_PIN(fnc)    \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, (int*) &i1);       \
-    f2 = fnc(f2, (int2*) &i2);      \
-    f3 = fnc(f3, (int3*) &i3);      \
-    f4 = fnc(f4, (int4*) &i4);
-
-#define TEST_FN_FUNC_FN_FN_PIN(fnc) \
-    rsDebug("Testing " #fnc, 0);    \
-    f1 = fnc(f1, f1, (int*) &i1);   \
-    f2 = fnc(f2, f2, (int2*) &i2);  \
-    f3 = fnc(f3, f3, (int3*) &i3);  \
-    f4 = fnc(f4, f4, (int4*) &i4);
-
-#define TEST_IN_FUNC_FN(fnc)        \
-    rsDebug("Testing " #fnc, 0);    \
-    i1 = fnc(f1);                   \
-    i2 = fnc(f2);                   \
-    i3 = fnc(f3);                   \
-    i4 = fnc(f4);
-
-static bool test_fp_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_FN_FUNC_FN(acos);
-    TEST_FN_FUNC_FN(acosh);
-    TEST_FN_FUNC_FN(acospi);
-    TEST_FN_FUNC_FN(asin);
-    TEST_FN_FUNC_FN(asinh);
-    TEST_FN_FUNC_FN(asinpi);
-    TEST_FN_FUNC_FN(atan);
-    TEST_FN_FUNC_FN_FN(atan2);
-    TEST_FN_FUNC_FN(atanh);
-    TEST_FN_FUNC_FN(atanpi);
-    TEST_FN_FUNC_FN_FN(atan2pi);
-    TEST_FN_FUNC_FN(cbrt);
-    TEST_FN_FUNC_FN(ceil);
-    TEST_FN_FUNC_FN_FN_FN(clamp);
-    TEST_FN_FUNC_FN_FN_F(clamp);
-    TEST_FN_FUNC_FN_FN(copysign);
-    TEST_FN_FUNC_FN(cos);
-    TEST_FN_FUNC_FN(cosh);
-    TEST_FN_FUNC_FN(cospi);
-    TEST_F34_FUNC_F34_F34(cross);
-    TEST_FN_FUNC_FN(degrees);
-    TEST_F_FUNC_FN_FN(distance);
-    TEST_F_FUNC_FN_FN(dot);
-    TEST_FN_FUNC_FN(erfc);
-    TEST_FN_FUNC_FN(erf);
-    TEST_FN_FUNC_FN(exp);
-    TEST_FN_FUNC_FN(exp2);
-    TEST_FN_FUNC_FN(exp10);
-    TEST_FN_FUNC_FN(expm1);
-    TEST_FN_FUNC_FN(fabs);
-    TEST_FN_FUNC_FN_FN(fdim);
-    TEST_FN_FUNC_FN(floor);
-    TEST_FN_FUNC_FN_FN_FN(fma);
-    TEST_FN_FUNC_FN_FN(fmax);
-    TEST_FN_FUNC_FN_F(fmax);
-    TEST_FN_FUNC_FN_FN(fmin);
-    TEST_FN_FUNC_FN_F(fmin);
-    TEST_FN_FUNC_FN_FN(fmod);
-    TEST_FN_FUNC_FN_PFN(fract);
-    TEST_FN_FUNC_FN_PIN(frexp);
-    TEST_FN_FUNC_FN_FN(hypot);
-    TEST_IN_FUNC_FN(ilogb);
-    TEST_FN_FUNC_FN_IN(ldexp);
-    TEST_FN_FUNC_FN_I(ldexp);
-    TEST_F_FUNC_FN(length);
-    TEST_FN_FUNC_FN(lgamma);
-    TEST_FN_FUNC_FN_PIN(lgamma);
-    TEST_FN_FUNC_FN(log);
-    TEST_FN_FUNC_FN(log2);
-    TEST_FN_FUNC_FN(log10);
-    TEST_FN_FUNC_FN(log1p);
-    TEST_FN_FUNC_FN(logb);
-    TEST_FN_FUNC_FN_FN_FN(mad);
-    TEST_FN_FUNC_FN_FN(max);
-    TEST_FN_FUNC_FN_F(max);
-    TEST_FN_FUNC_FN_FN(min);
-    TEST_FN_FUNC_FN_F(min);
-    TEST_FN_FUNC_FN_FN_FN(mix);
-    TEST_FN_FUNC_FN_FN_F(mix);
-    TEST_FN_FUNC_FN_PFN(modf);
-    // nan
-    TEST_FN_FUNC_FN_FN(nextafter);
-    TEST_FN_FUNC_FN(normalize);
-    TEST_FN_FUNC_FN_FN(pow);
-    TEST_FN_FUNC_FN_IN(pown);
-    TEST_FN_FUNC_FN_FN(powr);
-    TEST_FN_FUNC_FN(radians);
-    TEST_FN_FUNC_FN_FN(remainder);
-    TEST_FN_FUNC_FN_FN_PIN(remquo);
-    TEST_FN_FUNC_FN(rint);
-    TEST_FN_FUNC_FN_IN(rootn);
-    TEST_FN_FUNC_FN(round);
-    TEST_FN_FUNC_FN(rsqrt);
-    TEST_FN_FUNC_FN(sign);
-    TEST_FN_FUNC_FN(sin);
-    TEST_FN_FUNC_FN_PFN(sincos);
-    TEST_FN_FUNC_FN(sinh);
-    TEST_FN_FUNC_FN(sinpi);
-    TEST_FN_FUNC_FN(sqrt);
-    TEST_FN_FUNC_FN_FN(step);
-    TEST_FN_FUNC_FN_F(step);
-    TEST_FN_FUNC_FN(tan);
-    TEST_FN_FUNC_FN(tanh);
-    TEST_FN_FUNC_FN(tanpi);
-    TEST_FN_FUNC_FN(tgamma);
-    TEST_FN_FUNC_FN(trunc);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_fp_math FAILED", time);
-    }
-    else {
-        rsDebug("test_fp_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_int_math(uint32_t index) {
-    bool failed = false;
-    start();
-
-    TEST_UIN_FUNC_IN(abs);
-    TEST_IN_FUNC_IN(clz);
-    TEST_IN_FUNC_IN_IN(min);
-    TEST_IN_FUNC_IN_IN(max);
-    TEST_I_FUNC_I_I_I(rsClamp);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_int_math FAILED", time);
-    }
-    else {
-        rsDebug("test_int_math PASSED", time);
-    }
-
-    return failed;
-}
-
-static bool test_basic_operators() {
-    bool failed = false;
-    int i = 0;
-
-    TEST_INT_OP(+);
-    TEST_INT_OP(-);
-    TEST_INT_OP(*);
-    TEST_INT_OP(/);
-    TEST_INT_OP(%);
-    TEST_INT_OP(<<);
-    TEST_INT_OP(>>);
-
-    if (failed) {
-        rsDebug("test_basic_operators FAILED", 0);
-    }
-    else {
-        rsDebug("test_basic_operators PASSED", 0);
-    }
-
-    return failed;
-}
-
-#define TEST_CVT(to, from, type)                        \
-rsDebug("Testing convert from " #from " to " #to, 0);   \
-to##1 = from##1;                                        \
-to##2 = convert_##type##2(from##2);                     \
-to##3 = convert_##type##3(from##3);                     \
-to##4 = convert_##type##4(from##4);
-
-#define TEST_CVT_MATRIX(to, type)   \
-TEST_CVT(to, c, type);              \
-TEST_CVT(to, uc, type);             \
-TEST_CVT(to, s, type);              \
-TEST_CVT(to, us, type);             \
-TEST_CVT(to, i, type);              \
-TEST_CVT(to, ui, type);             \
-TEST_CVT(to, f, type);              \
-
-static bool test_convert() {
-    bool failed = false;
-
-    TEST_CVT_MATRIX(c, char);
-    TEST_CVT_MATRIX(uc, uchar);
-    TEST_CVT_MATRIX(s, short);
-    TEST_CVT_MATRIX(us, ushort);
-    TEST_CVT_MATRIX(i, int);
-    TEST_CVT_MATRIX(ui, uint);
-    TEST_CVT_MATRIX(f, float);
-
-    if (failed) {
-        rsDebug("test_convert FAILED", 0);
-    }
-    else {
-        rsDebug("test_convert PASSED", 0);
-    }
-
-    return failed;
-}
-
-void math_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_convert();
-    failed |= test_fp_math(index);
-    failed |= test_int_math(index);
-    failed |= test_basic_operators();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/primitives.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/primitives.rs
deleted file mode 100644
index ce451da..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/primitives.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool test_primitive_types(uint32_t index) {
-    bool failed = false;
-    start();
-
-    _RS_ASSERT(floatTest == 2.99f);
-    _RS_ASSERT(doubleTest == 3.05);
-    _RS_ASSERT(charTest == -16);
-    _RS_ASSERT(shortTest == -32);
-    _RS_ASSERT(intTest == -64);
-    _RS_ASSERT(longTest == 17179869185l);
-    _RS_ASSERT(longlongTest == 68719476735l);
-
-    _RS_ASSERT(ucharTest == 8);
-    _RS_ASSERT(ushortTest == 16);
-    _RS_ASSERT(uintTest == 32);
-    _RS_ASSERT(ulongTest == 4611686018427387903L);
-    _RS_ASSERT(int64_tTest == -17179869184l);
-    _RS_ASSERT(uint64_tTest == 117179869185l);
-
-    float time = end(index);
-
-    if (failed) {
-        rsDebug("test_primitives FAILED", time);
-    }
-    else {
-        rsDebug("test_primitives PASSED", time);
-    }
-
-    return failed;
-}
-
-void primitives_test(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= test_primitive_types(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/refcount.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/refcount.rs
deleted file mode 100644
index 4ea70e2..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/refcount.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "shared.rsh"
-
-// Testing reference counting of RS object types
-
-rs_allocation globalA;
-static rs_allocation staticGlobalA;
-
-void refcount_test() {
-    staticGlobalA = globalA;
-    rsClearObject(&globalA);
-    rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rsdebug.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rsdebug.rs
deleted file mode 100644
index f7942a5..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rsdebug.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "shared.rsh"
-
-// Testing primitive types
-float floatTest = 1.99f;
-double doubleTest = 2.05;
-char charTest = -8;
-short shortTest = -16;
-int intTest = -32;
-long longTest = 17179869184l; // 1 << 34
-long long longlongTest = 68719476736l; // 1 << 36
-
-uchar ucharTest = 8;
-ushort ushortTest = 16;
-uint uintTest = 32;
-ulong ulongTest = 4611686018427387904L;
-int64_t int64_tTest = -17179869184l; // - 1 << 34
-uint64_t uint64_tTest = 117179869184l;
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    // For this reason, none of the outputs are actually checked.
-
-    rsDebug("floatTest", floatTest);
-    rsDebug("doubleTest", doubleTest);
-    rsDebug("charTest", charTest);
-    rsDebug("shortTest", shortTest);
-    rsDebug("intTest", intTest);
-    rsDebug("longTest", longTest);
-    rsDebug("longlongTest", longlongTest);
-
-    rsDebug("ucharTest", ucharTest);
-    rsDebug("ushortTest", ushortTest);
-    rsDebug("uintTest", uintTest);
-    rsDebug("ulongTest", ulongTest);
-    rsDebug("int64_tTest", int64_tTest);
-    rsDebug("uint64_tTest", uint64_tTest);
-
-    return failed;
-}
-
-void test_rsdebug(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rsdebug_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rsdebug_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rslist.rs
deleted file mode 100644
index b3d8b9e..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rslist.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (C) 2009 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.
-
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_v14)
-
-#include "rs_graphics.rsh"
-
-float gDY;
-
-rs_font gFont;
-
-typedef struct ListAllocs_s {
-    rs_allocation text;
-    int result;
-} ListAllocs;
-
-ListAllocs *gList;
-
-void init() {
-    gDY = 0.0f;
-}
-
-int textPos = 0;
-
-int root(void) {
-
-    rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-    rsgClearDepth(1.0f);
-
-    textPos -= (int)gDY*2;
-    gDY *= 0.95;
-
-    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-    rsgBindFont(gFont);
-
-    rs_allocation listAlloc;
-    listAlloc = rsGetAllocation(gList);
-    int allocSize = rsAllocationGetDimX(listAlloc);
-
-    int width = rsgGetWidth();
-    int height = rsgGetHeight();
-
-    int itemHeight = 80;
-    int totalItemHeight = itemHeight * allocSize;
-
-    /* Prevent scrolling above the top of the list */
-    int firstItem = height - totalItemHeight;
-    if (firstItem < 0) {
-        firstItem = 0;
-    }
-
-    /* Prevent scrolling past the last line of the list */
-    int lastItem = -1 * (totalItemHeight - height);
-    if (lastItem > 0) {
-        lastItem = 0;
-    }
-
-    if (textPos > firstItem) {
-        textPos = firstItem;
-    }
-    else if (textPos < lastItem) {
-        textPos = lastItem;
-    }
-
-    int currentYPos = itemHeight + textPos;
-
-    for(int i = 0; i < allocSize; i ++) {
-        if(currentYPos - itemHeight > height) {
-            break;
-        }
-
-        if(currentYPos > 0) {
-            switch(gList[i].result) {
-                case 1: /* Passed */
-                    rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f);
-                    break;
-                case -1: /* Failed */
-                    rsgFontColor(0.9f, 0.5f, 0.5f, 1.0f);
-                    break;
-                case 0: /* Still Testing */
-                    rsgFontColor(0.9f, 0.9f, 0.5f, 1.0f);
-                    break;
-                default: /* Unknown */
-                    rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f);
-                    break;
-            }
-            rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0);
-            rsgDrawText(gList[i].text, 30, currentYPos - 32);
-        }
-        currentYPos += itemHeight;
-    }
-
-    return 10;
-}
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rstime.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rstime.rs
deleted file mode 100644
index 5e3e078..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rstime.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "shared.rsh"
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_time_t curTime = rsTime(0);
-    rs_tm tm;
-    rsDebug("curTime", curTime);
-
-    rsLocaltime(&tm, &curTime);
-
-    rsDebug("tm.tm_sec", tm.tm_sec);
-    rsDebug("tm.tm_min", tm.tm_min);
-    rsDebug("tm.tm_hour", tm.tm_hour);
-    rsDebug("tm.tm_mday", tm.tm_mday);
-    rsDebug("tm.tm_mon", tm.tm_mon);
-    rsDebug("tm.tm_year", tm.tm_year);
-    rsDebug("tm.tm_wday", tm.tm_wday);
-    rsDebug("tm.tm_yday", tm.tm_yday);
-    rsDebug("tm.tm_isdst", tm.tm_isdst);
-
-    // Test a specific time (only valid for PST localtime)
-    curTime = 1294438893;
-    rsLocaltime(&tm, &curTime);
-
-    _RS_ASSERT(tm.tm_sec == 33);
-    _RS_ASSERT(tm.tm_min == 21);
-    _RS_ASSERT(tm.tm_hour == 14);
-    _RS_ASSERT(tm.tm_mday == 7);
-    _RS_ASSERT(tm.tm_mon == 0);
-    _RS_ASSERT(tm.tm_year == 111);
-    _RS_ASSERT(tm.tm_wday == 5);
-    _RS_ASSERT(tm.tm_yday == 6);
-    _RS_ASSERT(tm.tm_isdst == 0);
-
-    return failed;
-}
-
-void test_rstime(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstime_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstime_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rstypes.rs
deleted file mode 100644
index 22d9c13..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/rstypes.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "shared.rsh"
-#include "rs_graphics.rsh"
-
-rs_element elementTest;
-rs_type typeTest;
-rs_allocation allocationTest;
-rs_sampler samplerTest;
-rs_script scriptTest;
-rs_mesh meshTest;
-rs_program_fragment program_fragmentTest;
-rs_program_vertex program_vertexTest;
-rs_program_raster program_rasterTest;
-rs_program_store program_storeTest;
-rs_font fontTest;
-
-rs_matrix4x4 matrix4x4Test;
-rs_matrix3x3 matrix3x3Test;
-rs_matrix2x2 matrix2x2Test;
-
-struct my_struct {
-    int i;
-    rs_font fontTestStruct;
-};
-
-static bool basic_test(uint32_t index) {
-    bool failed = false;
-
-    rs_matrix4x4 matrix4x4TestLocal;
-    rs_matrix3x3 matrix3x3TestLocal;
-    rs_matrix2x2 matrix2x2TestLocal;
-
-    // This test focuses primarily on compilation-time, not run-time.
-    rs_element elementTestLocal;
-    rs_type typeTestLocal;
-    rs_allocation allocationTestLocal;
-    rs_sampler samplerTestLocal;
-    rs_script scriptTestLocal;
-    rs_mesh meshTestLocal;
-    rs_program_fragment program_fragmentTestLocal;
-    rs_program_vertex program_vertexTestLocal;
-    rs_program_raster program_rasterTestLocal;
-    rs_program_store program_storeTestLocal;
-    rs_font fontTestLocal;
-
-    rs_font fontTestLocalArray[4];
-
-    rs_font fontTestLocalPreInit = fontTest;
-
-    struct my_struct structTest;
-
-    fontTestLocal = fontTest;
-    //allocationTestLocal = allocationTest;
-
-    fontTest = fontTestLocal;
-    //allocationTest = allocationTestLocal;
-
-    /*for (int i = 0; i < 4; i++) {
-        fontTestLocalArray[i] = fontTestLocal;
-    }*/
-
-    /*fontTest = fontTestLocalArray[3];*/
-
-    return failed;
-}
-
-void test_rstypes(uint32_t index, int test_num) {
-    bool failed = false;
-    failed |= basic_test(index);
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-        rsDebug("rstypes_test FAILED", -1);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-        rsDebug("rstypes_test PASSED", 0);
-    }
-}
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/shared.rsh b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/shared.rsh
deleted file mode 100644
index 4a7151f..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/shared.rsh
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_v14)
-
-typedef struct TestResult_s {
-    rs_allocation name;
-    bool pass;
-    float score;
-    int64_t time;
-} TestResult;
-//TestResult *g_results;
-
-static int64_t g_time;
-
-static void start(void) {
-    g_time = rsUptimeMillis();
-}
-
-static float end(uint32_t idx) {
-    int64_t t = rsUptimeMillis() - g_time;
-    //g_results[idx].time = t;
-    //rsDebug("test time", (int)t);
-    return ((float)t) / 1000.f;
-}
-
-#define _RS_ASSERT(b) \
-do { \
-    if (!(b)) { \
-        failed = true; \
-        rsDebug(#b " FAILED", 0); \
-    } \
-\
-} while (0)
-
-/* These constants must match those in UnitTest.java */
-static const int RS_MSG_TEST_PASSED = 100;
-static const int RS_MSG_TEST_FAILED = 101;
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/test_root.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/test_root.rs
deleted file mode 100644
index 88fe34a..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/test_root.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.rs.test_v14)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-
-typedef struct TestResult {
-    rs_allocation name;
-    bool pass;
-    float score;
-} TestResult_t;
-TestResult_t *results;
-
-int root() {
-
-    return 0;
-}
-
-
diff --git a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/vector.rs b/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/vector.rs
deleted file mode 100644
index 0430a2f..0000000
--- a/tests/RenderScriptTests/tests_v14/src/com/android/rs/test/vector.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "shared.rsh"
-
-// Testing vector types
-float2 f2 = { 1.0f, 2.0f };
-float3 f3 = { 1.0f, 2.0f, 3.0f };
-float4 f4 = { 1.0f, 2.0f, 3.0f, 4.0f };
-
-double2 d2 = { 1.0, 2.0 };
-double3 d3 = { 1.0, 2.0, 3.0 };
-double4 d4 = { 1.0, 2.0, 3.0, 4.0 };
-
-char2 i8_2 = { 1, 2 };
-char3 i8_3 = { 1, 2, 3 };
-char4 i8_4 = { 1, 2, 3, 4 };
-
-uchar2 u8_2 = { 1, 2 };
-uchar3 u8_3 = { 1, 2, 3 };
-uchar4 u8_4 = { 1, 2, 3, 4 };
-
-short2 i16_2 = { 1, 2 };
-short3 i16_3 = { 1, 2, 3 };
-short4 i16_4 = { 1, 2, 3, 4 };
-
-ushort2 u16_2 = { 1, 2 };
-ushort3 u16_3 = { 1, 2, 3 };
-ushort4 u16_4 = { 1, 2, 3, 4 };
-
-int2 i32_2 = { 1, 2 };
-int3 i32_3 = { 1, 2, 3 };
-int4 i32_4 = { 1, 2, 3, 4 };
-
-uint2 u32_2 = { 1, 2 };
-uint3 u32_3 = { 1, 2, 3 };
-uint4 u32_4 = { 1, 2, 3, 4 };
-
-long2 i64_2 = { 1, 2 };
-long3 i64_3 = { 1, 2, 3 };
-long4 i64_4 = { 1, 2, 3, 4 };
-
-ulong2 u64_2 = { 1, 2 };
-ulong3 u64_3 = { 1, 2, 3 };
-ulong4 u64_4 = { 1, 2, 3, 4 };
-
-static bool test_vector_types() {
-    bool failed = false;
-
-    rsDebug("Testing F32", 0);
-    _RS_ASSERT(f2.x == 2.99f);
-    _RS_ASSERT(f2.y == 3.99f);
-
-    _RS_ASSERT(f3.x == 2.99f);
-    _RS_ASSERT(f3.y == 3.99f);
-    _RS_ASSERT(f3.z == 4.99f);
-
-    _RS_ASSERT(f4.x == 2.99f);
-    _RS_ASSERT(f4.y == 3.99f);
-    _RS_ASSERT(f4.z == 4.99f);
-    _RS_ASSERT(f4.w == 5.99f);
-
-    rsDebug("Testing F64", 0);
-    _RS_ASSERT(d2.x == 2.99);
-    _RS_ASSERT(d2.y == 3.99);
-
-    _RS_ASSERT(d3.x == 2.99);
-    _RS_ASSERT(d3.y == 3.99);
-    _RS_ASSERT(d3.z == 4.99);
-
-    _RS_ASSERT(d4.x == 2.99);
-    _RS_ASSERT(d4.y == 3.99);
-    _RS_ASSERT(d4.z == 4.99);
-    _RS_ASSERT(d4.w == 5.99);
-
-    rsDebug("Testing I8", 0);
-    _RS_ASSERT(i8_2.x == 2);
-    _RS_ASSERT(i8_2.y == 3);
-
-    _RS_ASSERT(i8_3.x == 2);
-    _RS_ASSERT(i8_3.y == 3);
-    _RS_ASSERT(i8_3.z == 4);
-
-    _RS_ASSERT(i8_4.x == 2);
-    _RS_ASSERT(i8_4.y == 3);
-    _RS_ASSERT(i8_4.z == 4);
-    _RS_ASSERT(i8_4.w == 5);
-
-    rsDebug("Testing U8", 0);
-    _RS_ASSERT(u8_2.x == 2);
-    _RS_ASSERT(u8_2.y == 3);
-
-    _RS_ASSERT(u8_3.x == 2);
-    _RS_ASSERT(u8_3.y == 3);
-    _RS_ASSERT(u8_3.z == 4);
-
-    _RS_ASSERT(u8_4.x == 2);
-    _RS_ASSERT(u8_4.y == 3);
-    _RS_ASSERT(u8_4.z == 4);
-    _RS_ASSERT(u8_4.w == 5);
-
-    rsDebug("Testing I16", 0);
-    _RS_ASSERT(i16_2.x == 2);
-    _RS_ASSERT(i16_2.y == 3);
-
-    _RS_ASSERT(i16_3.x == 2);
-    _RS_ASSERT(i16_3.y == 3);
-    _RS_ASSERT(i16_3.z == 4);
-
-    _RS_ASSERT(i16_4.x == 2);
-    _RS_ASSERT(i16_4.y == 3);
-    _RS_ASSERT(i16_4.z == 4);
-    _RS_ASSERT(i16_4.w == 5);
-
-    rsDebug("Testing U16", 0);
-    _RS_ASSERT(u16_2.x == 2);
-    _RS_ASSERT(u16_2.y == 3);
-
-    _RS_ASSERT(u16_3.x == 2);
-    _RS_ASSERT(u16_3.y == 3);
-    _RS_ASSERT(u16_3.z == 4);
-
-    _RS_ASSERT(u16_4.x == 2);
-    _RS_ASSERT(u16_4.y == 3);
-    _RS_ASSERT(u16_4.z == 4);
-    _RS_ASSERT(u16_4.w == 5);
-
-    rsDebug("Testing I32", 0);
-    _RS_ASSERT(i32_2.x == 2);
-    _RS_ASSERT(i32_2.y == 3);
-
-    _RS_ASSERT(i32_3.x == 2);
-    _RS_ASSERT(i32_3.y == 3);
-    _RS_ASSERT(i32_3.z == 4);
-
-    _RS_ASSERT(i32_4.x == 2);
-    _RS_ASSERT(i32_4.y == 3);
-    _RS_ASSERT(i32_4.z == 4);
-    _RS_ASSERT(i32_4.w == 5);
-
-    rsDebug("Testing U32", 0);
-    _RS_ASSERT(u32_2.x == 2);
-    _RS_ASSERT(u32_2.y == 3);
-
-    _RS_ASSERT(u32_3.x == 2);
-    _RS_ASSERT(u32_3.y == 3);
-    _RS_ASSERT(u32_3.z == 4);
-
-    _RS_ASSERT(u32_4.x == 2);
-    _RS_ASSERT(u32_4.y == 3);
-    _RS_ASSERT(u32_4.z == 4);
-    _RS_ASSERT(u32_4.w == 5);
-
-    rsDebug("Testing I64", 0);
-    _RS_ASSERT(i64_2.x == 2);
-    _RS_ASSERT(i64_2.y == 3);
-
-    _RS_ASSERT(i64_3.x == 2);
-    _RS_ASSERT(i64_3.y == 3);
-    _RS_ASSERT(i64_3.z == 4);
-
-    _RS_ASSERT(i64_4.x == 2);
-    _RS_ASSERT(i64_4.y == 3);
-    _RS_ASSERT(i64_4.z == 4);
-    _RS_ASSERT(i64_4.w == 5);
-
-    rsDebug("Testing U64", 0);
-    _RS_ASSERT(u64_2.x == 2);
-    _RS_ASSERT(u64_2.y == 3);
-
-    _RS_ASSERT(u64_3.x == 2);
-    _RS_ASSERT(u64_3.y == 3);
-    _RS_ASSERT(u64_3.z == 4);
-
-    _RS_ASSERT(u64_4.x == 2);
-    _RS_ASSERT(u64_4.y == 3);
-    _RS_ASSERT(u64_4.z == 4);
-    _RS_ASSERT(u64_4.w == 5);
-
-    if (failed) {
-        rsDebug("test_vector FAILED", 0);
-    }
-    else {
-        rsDebug("test_vector PASSED", 0);
-    }
-
-    return failed;
-}
-
-void vector_test() {
-    bool failed = false;
-    failed |= test_vector_types();
-
-    if (failed) {
-        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
-    }
-    else {
-        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
-    }
-}
-
diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk
new file mode 100644
index 0000000..60ef92a
--- /dev/null
+++ b/tests/SharedLibrary/client/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_APK_LIBRARIES := SharedLibrary
+
+LOCAL_PACKAGE_NAME := SharedLibraryClient
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SharedLibrary/client/AndroidManifest.xml b/tests/SharedLibrary/client/AndroidManifest.xml
new file mode 100644
index 0000000..c6a43c0
--- /dev/null
+++ b/tests/SharedLibrary/client/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.test.lib_client">
+    <application android:label="@string/app_title">
+        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="com.google.android.test.shared_library" />
+        <activity android:name="ActivityMain">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/SharedLibrary/client/res/values/strings.xml b/tests/SharedLibrary/client/res/values/strings.xml
new file mode 100644
index 0000000..3757a25
--- /dev/null
+++ b/tests/SharedLibrary/client/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+    <string name="app_title">SharedLibrary client</string>
+</resources>
diff --git a/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java
new file mode 100644
index 0000000..d6121a5
--- /dev/null
+++ b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java
@@ -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.
+ */
+
+package com.google.android.test.lib_client;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+import com.google.android.test.shared_library.SharedLibraryMain;
+
+public class ActivityMain extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        TextView content = new TextView(this);
+        content.setText("Library version: " + SharedLibraryMain.getVersion(this) + "!");
+
+        SharedLibraryMain.ensureVersion(this, SharedLibraryMain.VERSION_BASE);
+        setContentView(content);
+    }
+}
diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk
new file mode 100644
index 0000000..c19e23a
--- /dev/null
+++ b/tests/SharedLibrary/lib/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SharedLibrary
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SharedLibrary/lib/AndroidManifest.xml b/tests/SharedLibrary/lib/AndroidManifest.xml
new file mode 100644
index 0000000..31fac20
--- /dev/null
+++ b/tests/SharedLibrary/lib/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.test.shared_library"
+    android:versionCode="2">
+    <application android:label="SharedLibrary">
+        <library android:name="com.google.android.test.shared_library" />
+        <activity android:name="ActivityMain">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/SharedLibrary/lib/res/values/strings.xml b/tests/SharedLibrary/lib/res/values/strings.xml
new file mode 100644
index 0000000..bbfb0b4
--- /dev/null
+++ b/tests/SharedLibrary/lib/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="upgrade_title">Upgrade required</string>
+    <string name="upgrade_body"><xliff:g id="app">%1$s</xliff:g> requires a newer version
+            of <xliff:g id="lib">%2$s</xliff:g> to run.</string>
+    <string name="upgrade_button">Upgrade</string>
+</resources>
diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java
new file mode 100644
index 0000000..895aced
--- /dev/null
+++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/ActivityMain.java
@@ -0,0 +1,32 @@
+/*
+ * 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.google.android.test.shared_library;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ActivityMain extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        TextView content = new TextView(this);
+        content.setText("Dummy main entry for this apk; not really needed...");
+        setContentView(content);
+    }
+}
diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.java
new file mode 100644
index 0000000..2c61b77
--- /dev/null
+++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/SharedLibraryMain.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.google.android.test.shared_library;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+public class SharedLibraryMain {
+    static String LIBRARY_PACKAGE = "com.google.android.test.shared_library";
+
+    /**
+     * Base version of the library.
+     */
+    public static int VERSION_BASE = 1;
+
+    /**
+     * The second version of the library.
+     */
+    public static int VERSION_SECOND = 2;
+
+    /**
+     * Return the version number of the currently installed library.
+     */
+    public static int getVersion(Context context) {
+        PackageInfo pi = null;
+        try {
+            pi = context.getPackageManager().getPackageInfo(LIBRARY_PACKAGE, 0);
+            return pi.versionCode;
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Can't find my package!", e);
+        }
+    }
+
+    /**
+     * Check that the library's version is at least the given minimum version,
+     * displaying a dialog to have the user install an update if that is not true.
+     * The dialog is displayed as a DialogFragment in your activity if a newer
+     * version is needed.  If a newer version is needed, false is returned.
+     */
+    public static boolean ensureVersion(final Activity activity, int minVersion) {
+        final FragmentManager fm = activity.getFragmentManager();
+        final String dialogTag = LIBRARY_PACKAGE + ":version";
+        Fragment curDialog = fm.findFragmentByTag(dialogTag);
+
+        if (getVersion(activity) >= minVersion) {
+            // Library version is sufficient.  Make sure any version dialog
+            // we had shown is removed before returning.
+            if (curDialog != null) {
+                fm.beginTransaction().remove(curDialog).commitAllowingStateLoss();
+            }
+            return true;
+        }
+
+        // The current version of the library does not meet the required version.
+        // If we don't already have a version dialog displayed, display it now.
+        if (curDialog == null) {
+            curDialog = new VersionDialog();
+            fm.beginTransaction().add(curDialog, dialogTag).commitAllowingStateLoss();
+        }
+
+        // Tell the caller that the current version is not sufficient.
+        return false;
+    }
+}
diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/VersionDialog.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/VersionDialog.java
new file mode 100644
index 0000000..f457532
--- /dev/null
+++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/VersionDialog.java
@@ -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.
+ */
+
+package com.google.android.test.shared_library;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * This is the dialog we show when the library's version is older than
+ * the version the app needs.
+ */
+public class VersionDialog extends DialogFragment {
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final Activity activity = getActivity();
+
+        // Need to use our library's resources for showing the dialog.
+        final Context context;
+        try {
+            context = activity.createPackageContext(SharedLibraryMain.LIBRARY_PACKAGE, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Can't find my package!", e);
+        }
+
+        final Resources res = context.getResources();
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setTitle(res.getText(R.string.upgrade_title));
+        builder.setMessage(res.getString(R.string.upgrade_body,
+                activity.getApplicationInfo().loadLabel(activity.getPackageManager()),
+                context.getApplicationInfo().loadLabel(context.getPackageManager())));
+        builder.setPositiveButton(res.getText(R.string.upgrade_button),
+                new Dialog.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        // Launch play store into the details of our app.
+                        try {
+                            activity.startActivity(new Intent(Intent.ACTION_VIEW,
+                                    Uri.parse("market://details?id="
+                                            + SharedLibraryMain.LIBRARY_PACKAGE)));
+                        } catch (android.content.ActivityNotFoundException anfe) {
+                            activity.startActivity(new Intent(Intent.ACTION_VIEW,
+                                    Uri.parse("http://play.google.com/store/apps/details?id="
+                                            + SharedLibraryMain.LIBRARY_PACKAGE)));
+                        }
+                    }
+                });
+        return builder.create();
+    }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index 5d0b155..9862116 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -49,6 +49,8 @@
 {
     private final static String TAG = "NotificationTestList";
 
+    private final static String NOTIFY_TAG = "foo";
+
     NotificationManager mNM;
     Handler mHandler;
     int mStartDelay;
@@ -117,34 +119,34 @@
         public void onClick(View v) {
             switch (v.getId()) {
                 case R.id.clear_1:
-                    mNM.cancel(1);
+                    cancelNotification(1);
                     break;
                 case R.id.clear_2:
-                    mNM.cancel(2);
+                    cancelNotification(2);
                     break;
                 case R.id.clear_3:
-                    mNM.cancel(3);
+                    cancelNotification(3);
                     break;
                 case R.id.clear_4:
-                    mNM.cancel(4);
+                    cancelNotification(4);
                     break;
                 case R.id.clear_5:
-                    mNM.cancel(5);
+                    cancelNotification(5);
                     break;
                 case R.id.clear_6:
-                    mNM.cancel(6);
+                    cancelNotification(6);
                     break;
                 case R.id.clear_7:
-                    mNM.cancel(7);
+                    cancelNotification(7);
                     break;
                 case R.id.clear_8:
-                    mNM.cancel(8);
+                    cancelNotification(8);
                     break;
                 case R.id.clear_9:
-                    mNM.cancel(9);
+                    cancelNotification(9);
                     break;
                 case R.id.clear_10:
-                    mNM.cancel(10);
+                    cancelNotification(10);
                     break;
                 case R.id.notify_1:
                     sendNotification(1);
@@ -196,11 +198,15 @@
         final Notification n = buildNotification(id);
         mHandler.postDelayed(new Runnable() {
             public void run() {
-                mNM.notify(id, n);
+                mNM.notify(NOTIFY_TAG, id, n);
             }
         }, mStartDelay);
     }
 
+    private void cancelNotification(final int id) {
+        mNM.cancel(NOTIFY_TAG, id);
+    }
+
     private static CharSequence subst(CharSequence in, char ch, CharSequence sub) {
         int i=0;
         SpannableStringBuilder edit = new SpannableStringBuilder(in);
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 4345098..ba160b18 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -33,13 +33,10 @@
 import android.net.Uri;
 import android.os.SystemClock;
 import android.widget.RemoteViews;
-import android.widget.TextView;
-import android.widget.ProgressBar;
 import android.os.PowerManager;
 
 // private NM API
 import android.app.INotificationManager;
-import com.android.internal.statusbar.StatusBarNotification;
 
 public class NotificationTestList extends TestActivity
 {
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 5b88669..9b1658a 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -39,14 +39,14 @@
 LOCAL_C_INCLUDES += external/zlib
 LOCAL_C_INCLUDES += build/libs/host/include
 
-#LOCAL_WHOLE_STATIC_LIBRARIES := 
 LOCAL_STATIC_LIBRARIES := \
 	libhost \
 	libandroidfw \
 	libutils \
 	libcutils \
 	libexpat \
-	libpng
+	libpng \
+	liblog
 
 ifeq ($(HOST_OS),linux)
 LOCAL_LDLIBS += -lrt -ldl -lpthread
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 84f5a5c..cadac02 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -592,6 +592,10 @@
                         goto bail;
                     }
                     printf("uses-permission: %s\n", name.string());
+                    int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
+                    if (!req) {
+                        printf("optional-permission: %s\n", name.string());
+                    }
                 }
             }
         } else if (strcmp("badging", option) == 0) {
@@ -1033,6 +1037,10 @@
                                 hasWriteCallLogPermission = true;
                             }
                             printf("uses-permission:'%s'\n", name.string());
+                            int req = getIntegerAttribute(tree, REQUIRED_ATTR, NULL, 1);
+                            if (!req) {
+                                printf("optional-permission:'%s'\n", name.string());
+                            }
                         } else {
                             fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
                                     error.string());
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 59ae1a1..434b131 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Point;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 
@@ -348,11 +349,31 @@
     }
 
     @Override
+    public void getInitialDisplaySize(int displayId, Point size) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void getBaseDisplaySize(int displayId, Point size) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
     public void setForcedDisplaySize(int displayId, int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
     @Override
+    public int getInitialDisplayDensity(int displayId) {
+        return -1;
+    }
+
+    @Override
+    public int getBaseDisplayDensity(int displayId) {
+        return -1;
+    }
+
+    @Override
     public void setForcedDisplayDensity(int displayId, int density) throws RemoteException {
         // TODO Auto-generated method stub
     }
@@ -428,6 +449,10 @@
     }
 
     @Override
+    public void removeRotationWatcher(IRotationWatcher arg0) throws RemoteException {
+    }
+
+    @Override
     public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
         return false;
     }
diff --git a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java
index 7a6e52e..dc4f9c8 100644
--- a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Accessor.java
@@ -22,6 +22,6 @@
 public class InputMethodManager_Accessor {
 
     public static void resetInstance() {
-        InputMethodManager.mInstance = null;
+        InputMethodManager.sInstance = null;
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
index f056040..7c98847 100644
--- a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
@@ -35,28 +35,15 @@
     // ---- Overridden methods ----
 
     @LayoutlibDelegate
-    /*package*/ static InputMethodManager getInstance(Looper mainLooper) {
-        synchronized (InputMethodManager.mInstanceSync) {
-            if (InputMethodManager.mInstance != null) {
-                return InputMethodManager.mInstance;
+    /*package*/ static InputMethodManager getInstance() {
+        synchronized (InputMethodManager.class) {
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm == null) {
+                imm = new InputMethodManager(
+                        new BridgeIInputMethodManager(), Looper.getMainLooper());
+                InputMethodManager.sInstance = imm;
             }
-
-            InputMethodManager.mInstance = new InputMethodManager(new BridgeIInputMethodManager(),
-                    mainLooper);
+            return imm;
         }
-        return InputMethodManager.mInstance;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static InputMethodManager getInstance(Context context) {
-        synchronized (InputMethodManager.mInstanceSync) {
-            if (InputMethodManager.mInstance != null) {
-                return InputMethodManager.mInstance;
-            }
-
-            InputMethodManager.mInstance = new InputMethodManager(new BridgeIInputMethodManager(),
-                    Looper.myLooper());
-        }
-        return InputMethodManager.mInstance;
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index f109e39..cbefd3d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -232,7 +232,7 @@
         sCurrentContext = mContext;
 
         // create an InputMethodManager
-        InputMethodManager.getInstance(Looper.myLooper());
+        InputMethodManager.getInstance();
 
         LayoutLog currentLog = mParams.getLog();
         Bridge.setLog(currentLog);
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index dd57ae6..ad8de69 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -20,7 +20,8 @@
 LOCAL_STATIC_LIBRARIES := \
 	libutils \
 	libandroidfw \
-	libcutils
+	libcutils \
+	liblog
 
 ifeq ($(HOST_OS),linux)
 LOCAL_LDLIBS += -ldl -lpthread
diff --git a/tools/validatekeymaps/Android.mk b/tools/validatekeymaps/Android.mk
index fce2e93..90fbc08 100644
--- a/tools/validatekeymaps/Android.mk
+++ b/tools/validatekeymaps/Android.mk
@@ -20,7 +20,8 @@
 LOCAL_STATIC_LIBRARIES := \
 	libandroidfw \
 	libutils \
-	libcutils
+	libcutils \
+	liblog
 
 ifeq ($(HOST_OS),linux)
 LOCAL_LDLIBS += -ldl -lpthread
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bef5824..f093b52 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -71,6 +71,8 @@
 
     DhcpInfo getDhcpInfo();
 
+    boolean isScanningAlwaysAvailable();
+
     boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws);
 
     void updateWifiLockWorkSource(IBinder lock, in WorkSource ws);
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index eb2f74c..7b1a71f 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -395,6 +395,23 @@
         return ret;
     }
 
+    void disableAllNetworks() {
+        boolean networkDisabled = false;
+        for(WifiConfiguration config : mConfiguredNetworks.values()) {
+            if(config != null && config.status != Status.DISABLED) {
+                if(mWifiNative.disableNetwork(config.networkId)) {
+                    networkDisabled = true;
+                    config.status = Status.DISABLED;
+                } else {
+                    loge("Disable network failed on " + config.networkId);
+                }
+            }
+        }
+
+        if (networkDisabled) {
+            sendConfiguredNetworksChangedBroadcast();
+        }
+    }
     /**
      * Disable a network. Note that there is no saveConfig operation.
      * @param netId network to be disabled
@@ -1179,7 +1196,7 @@
             WifiConfiguration newConfig) {
         boolean ipChanged = false;
         boolean proxyChanged = false;
-        LinkProperties linkProperties = new LinkProperties();
+        LinkProperties linkProperties = null;
 
         switch (newConfig.ipAssignment) {
             case STATIC:
@@ -1245,10 +1262,10 @@
         }
 
         if (!ipChanged) {
-            addIpSettingsFromConfig(linkProperties, currentConfig);
+            linkProperties = copyIpSettingsFromConfig(currentConfig);
         } else {
             currentConfig.ipAssignment = newConfig.ipAssignment;
-            addIpSettingsFromConfig(linkProperties, newConfig);
+            linkProperties = copyIpSettingsFromConfig(newConfig);
             log("IP config changed SSID = " + currentConfig.SSID + " linkProperties: " +
                     linkProperties.toString());
         }
@@ -1274,8 +1291,9 @@
         return new NetworkUpdateResult(ipChanged, proxyChanged);
     }
 
-    private void addIpSettingsFromConfig(LinkProperties linkProperties,
-            WifiConfiguration config) {
+    private LinkProperties copyIpSettingsFromConfig(WifiConfiguration config) {
+        LinkProperties linkProperties = new LinkProperties();
+        linkProperties.setInterfaceName(config.linkProperties.getInterfaceName());
         for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
             linkProperties.addLinkAddress(linkAddr);
         }
@@ -1285,6 +1303,7 @@
         for (InetAddress dns : config.linkProperties.getDnses()) {
             linkProperties.addDns(dns);
         }
+        return linkProperties;
     }
 
     /**
@@ -1451,6 +1470,8 @@
         if (config.enterpriseConfig.migrateOldEapTlsNative(mWifiNative, netId)) {
             saveConfig();
         }
+
+        config.enterpriseConfig.migrateCerts(mKeyStore);
     }
 
     private String removeDoubleQuotes(String string) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 95ffb1c..f73a13c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -17,9 +17,9 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Process;
 import android.security.Credentials;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.org.bouncycastle.asn1.ASN1InputStream;
 import com.android.org.bouncycastle.asn1.ASN1Sequence;
@@ -481,7 +481,7 @@
         String caCertName = Credentials.CA_CERTIFICATE + name;
         if (mClientCertificate != null) {
             byte[] privKeyData = mClientPrivateKey.getEncoded();
-            ret = keyStore.importKey(privKeyName, privKeyData);
+            ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID);
             if (ret == false) {
                 return ret;
             }
@@ -489,7 +489,7 @@
             ret = putCertInKeyStore(keyStore, userCertName, mClientCertificate);
             if (ret == false) {
                 // Remove private key installed
-                keyStore.delKey(privKeyName);
+                keyStore.delKey(privKeyName, Process.WIFI_UID);
                 return ret;
             }
         }
@@ -499,8 +499,8 @@
             if (ret == false) {
                 if (mClientCertificate != null) {
                     // Remove client key+cert
-                    keyStore.delKey(privKeyName);
-                    keyStore.delete(userCertName);
+                    keyStore.delKey(privKeyName, Process.WIFI_UID);
+                    keyStore.delete(userCertName, Process.WIFI_UID);
                 }
                 return ret;
             }
@@ -525,7 +525,7 @@
             Certificate cert) {
         try {
             byte[] certData = Credentials.convertToPem(cert);
-            return keyStore.put(name, certData);
+            return keyStore.put(name, certData, Process.WIFI_UID);
         } catch (IOException e1) {
             return false;
         } catch (CertificateException e2) {
@@ -537,14 +537,14 @@
         String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
         // a valid client certificate is configured
         if (!TextUtils.isEmpty(client)) {
-            keyStore.delKey(Credentials.USER_PRIVATE_KEY + client);
-            keyStore.delete(Credentials.USER_CERTIFICATE + client);
+            keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID);
+            keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID);
         }
 
         String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
         // a valid ca certificate is configured
         if (!TextUtils.isEmpty(ca)) {
-            keyStore.delete(Credentials.CA_CERTIFICATE + ca);
+            keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID);
         }
     }
 
@@ -625,6 +625,29 @@
         return true;
     }
 
+    /** Migrate certs from global pool to wifi UID if not already done */
+    void migrateCerts(android.security.KeyStore keyStore) {
+        String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
+        // a valid client certificate is configured
+        if (!TextUtils.isEmpty(client)) {
+            if (!keyStore.contains(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID)) {
+                keyStore.duplicate(Credentials.USER_PRIVATE_KEY + client, -1,
+                        Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID);
+                keyStore.duplicate(Credentials.USER_CERTIFICATE + client, -1,
+                        Credentials.USER_CERTIFICATE + client, Process.WIFI_UID);
+            }
+        }
+
+        String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
+        // a valid ca certificate is configured
+        if (!TextUtils.isEmpty(ca)) {
+            if (!keyStore.contains(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID)) {
+                keyStore.duplicate(Credentials.CA_CERTIFICATE + ca, -1,
+                        Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID);
+            }
+        }
+    }
+
     private String removeDoubleQuotes(String string) {
         int length = string.length();
         if ((length > 1) && (string.charAt(0) == '"')
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index a2df64b..0c0a144 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -393,6 +393,30 @@
     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
 
     /**
+     * Activity Action: Show a system activity that allows the user to enable
+     * scans to be available even with Wi-Fi turned off.
+     *
+     * <p>Notification of the result of this activity is posted using the
+     * {@link android.app.Activity#onActivityResult} callback. The
+     * <code>resultCode</code>
+     * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
+     * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
+     * has rejected the request or an error has occurred.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
+            "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
+
+    /**
+     * Activity Action: Show a system activity that notifies the user that
+     * scanning is still available when Wi-Fi is turned off
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_NOTIFY_SCAN_ALWAYS_AVAILABLE =
+            "android.net.wifi.action.NOTIFY_SCAN_ALWAYS_AVAILABLE";
+
+    /**
      * Activity Action: Pick a Wi-Fi network to connect to.
      * <p>Input: Nothing.
      * <p>Output: Nothing.
@@ -763,6 +787,22 @@
     }
 
     /**
+     * Check if scanning is always available.
+     *
+     * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
+     * even when Wi-Fi is turned off.
+     *
+     * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
+     */
+    public boolean isScanningAlwaysAvailable() {
+        try {
+            return mService.isScanningAlwaysAvailable();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Tell the supplicant to persist the current list of configured networks.
      * <p>
      * Note: It is possible for this method to change the network IDs of
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 32cd2f6..f637e89 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -793,4 +793,14 @@
     public boolean p2pServDiscCancelReq(String id) {
         return doBooleanCommand("P2P_SERV_DISC_CANCEL_REQ " + id);
     }
+
+    /* Set the current mode of miracast operation.
+     *  0 = disabled
+     *  1 = operating as source
+     *  2 = operating as sink
+     */
+    public void setMiracastMode(int mode) {
+        // Note: optional feature on the driver. It is ok for this to fail.
+        doBooleanCommand("DRIVER MIRACAST " + mode);
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index d4ec289..c0a3bc1 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -134,7 +134,12 @@
     private boolean mEnableBackgroundScan = false;
     private int mRssiPollToken = 0;
     private int mReconnectCount = 0;
-    private boolean mIsScanMode = false;
+    /* 3 operational states for STA operation: CONNECT_MODE, SCAN_ONLY_MODE, SCAN_ONLY_WIFI_OFF_MODE
+    * In CONNECT_MODE, the STA can scan and connect to an access point
+    * In SCAN_ONLY_MODE, the STA can only scan for access points
+    * In SCAN_ONLY_WIFI_OFF_MODE, the STA can only scan for access points with wifi toggle being off
+    */
+    private int mOperationalMode = CONNECT_MODE;
     private boolean mScanResultIsPending = false;
     /* Tracks if state machine has received any screen state change broadcast yet.
      * We can miss one of these at boot.
@@ -285,8 +290,8 @@
     /* Supplicant commands after driver start*/
     /* Initiate a scan */
     static final int CMD_START_SCAN                       = BASE + 71;
-    /* Set scan mode. CONNECT_MODE or SCAN_ONLY_MODE */
-    static final int CMD_SET_SCAN_MODE                    = BASE + 72;
+    /* Set operational mode. CONNECT, SCAN ONLY, SCAN_ONLY with Wi-Fi off mode */
+    static final int CMD_SET_OPERATIONAL_MODE             = BASE + 72;
     /* Disconnect from a network */
     static final int CMD_DISCONNECT                       = BASE + 73;
     /* Reconnect to a network */
@@ -342,16 +347,13 @@
     public static final int CMD_DISABLE_P2P_REQ           = BASE + 132;
     public static final int CMD_DISABLE_P2P_RSP           = BASE + 133;
 
-    private static final int CONNECT_MODE   = 1;
-    private static final int SCAN_ONLY_MODE = 2;
+    public static final int CONNECT_MODE                   = 1;
+    public static final int SCAN_ONLY_MODE                 = 2;
+    public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE   = 3;
 
     private static final int SUCCESS = 1;
     private static final int FAILURE = -1;
 
-    /* Phone in emergency call back mode */
-    private static final int IN_ECM_STATE = 1;
-    private static final int NOT_IN_ECM_STATE = 0;
-
     /**
      * The maximum number of times we will retry a connection to an access point
      * for which we have failed in acquiring an IP address from DHCP. A value of
@@ -496,9 +498,6 @@
      */
     private final AtomicInteger mWifiApState = new AtomicInteger(WIFI_AP_STATE_DISABLED);
 
-    private final AtomicInteger mLastEnableUid = new AtomicInteger(Process.myUid());
-    private final AtomicInteger mLastApEnableUid = new AtomicInteger(Process.myUid());
-
     private static final int SCAN_REQUEST = 0;
     private static final String ACTION_START_SCAN =
         "com.android.server.WifiManager.action.START_SCAN";
@@ -623,7 +622,7 @@
                     @Override
                     public void onReceive(Context context, Intent intent) {
                        int counter = intent.getIntExtra(DELAYED_STOP_COUNTER, 0);
-                       sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, counter, 0));
+                       sendMessage(CMD_DELAYED_STOP_DRIVER, counter, 0);
                     }
                 },
                 new IntentFilter(ACTION_DELAYED_DRIVER_STOP));
@@ -714,8 +713,7 @@
     /**
      * TODO: doc
      */
-    public void setWifiEnabled(boolean enable) {
-        mLastEnableUid.set(Binder.getCallingUid());
+    public void setSupplicantRunning(boolean enable) {
         if (enable) {
             sendMessage(CMD_START_SUPPLICANT);
         } else {
@@ -726,10 +724,9 @@
     /**
      * TODO: doc
      */
-    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
-        mLastApEnableUid.set(Binder.getCallingUid());
+    public void setHostApRunning(WifiConfiguration wifiConfig, boolean enable) {
         if (enable) {
-            sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
+            sendMessage(CMD_START_AP, wifiConfig);
         } else {
             sendMessage(CMD_STOP_AP);
         }
@@ -818,27 +815,23 @@
     /**
      * TODO: doc
      */
-    public void setDriverStart(boolean enable, boolean ecm) {
+    public void setDriverStart(boolean enable) {
         if (enable) {
             sendMessage(CMD_START_DRIVER);
         } else {
-            sendMessage(obtainMessage(CMD_STOP_DRIVER, ecm ? IN_ECM_STATE : NOT_IN_ECM_STATE, 0));
+            sendMessage(CMD_STOP_DRIVER);
         }
     }
 
     public void captivePortalCheckComplete() {
-        sendMessage(obtainMessage(CMD_CAPTIVE_CHECK_COMPLETE));
+        sendMessage(CMD_CAPTIVE_CHECK_COMPLETE);
     }
 
     /**
      * TODO: doc
      */
-    public void setScanOnlyMode(boolean enable) {
-        if (enable) {
-            sendMessage(obtainMessage(CMD_SET_SCAN_MODE, SCAN_ONLY_MODE, 0));
-        } else {
-            sendMessage(obtainMessage(CMD_SET_SCAN_MODE, CONNECT_MODE, 0));
-        }
+    public void setOperationalMode(int mode) {
+        sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
     }
 
     /**
@@ -941,7 +934,7 @@
      * @param bssid BSSID of the network
      */
     public void addToBlacklist(String bssid) {
-        sendMessage(obtainMessage(CMD_BLACKLIST_NETWORK, bssid));
+        sendMessage(CMD_BLACKLIST_NETWORK, bssid);
     }
 
     /**
@@ -949,15 +942,15 @@
      *
      */
     public void clearBlacklist() {
-        sendMessage(obtainMessage(CMD_CLEAR_BLACKLIST));
+        sendMessage(CMD_CLEAR_BLACKLIST);
     }
 
     public void enableRssiPolling(boolean enabled) {
-       sendMessage(obtainMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0));
+       sendMessage(CMD_ENABLE_RSSI_POLL, enabled ? 1 : 0, 0);
     }
 
     public void enableBackgroundScanCommand(boolean enabled) {
-       sendMessage(obtainMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0));
+       sendMessage(CMD_ENABLE_BACKGROUND_SCAN, enabled ? 1 : 0, 0);
     }
 
     public void enableAllNetworks() {
@@ -969,7 +962,7 @@
      */
     public void startFilteringMulticastV4Packets() {
         mFilteringMulticastV4Packets.set(true);
-        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0));
+        sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V4, 0);
     }
 
     /**
@@ -977,21 +970,21 @@
      */
     public void stopFilteringMulticastV4Packets() {
         mFilteringMulticastV4Packets.set(false);
-        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0));
+        sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V4, 0);
     }
 
     /**
      * Start filtering Multicast v4 packets
      */
     public void startFilteringMulticastV6Packets() {
-        sendMessage(obtainMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0));
+        sendMessage(CMD_START_PACKET_FILTERING, MULTICAST_V6, 0);
     }
 
     /**
      * Stop filtering Multicast v4 packets
      */
     public void stopFilteringMulticastV6Packets() {
-        sendMessage(obtainMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0));
+        sendMessage(CMD_STOP_PACKET_FILTERING, MULTICAST_V6, 0);
     }
 
     /**
@@ -1001,7 +994,7 @@
      * @param enable true if enable, false otherwise
      */
     public void setHighPerfModeEnabled(boolean enable) {
-        sendMessage(obtainMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0));
+        sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);
     }
 
     /**
@@ -1015,7 +1008,7 @@
                     Settings.Global.WIFI_COUNTRY_CODE,
                     countryCode);
         }
-        sendMessage(obtainMessage(CMD_SET_COUNTRY_CODE, countryCode));
+        sendMessage(CMD_SET_COUNTRY_CODE, countryCode);
     }
 
     /**
@@ -1029,7 +1022,7 @@
                     Settings.Global.WIFI_FREQUENCY_BAND,
                     band);
         }
-        sendMessage(obtainMessage(CMD_SET_FREQUENCY_BAND, band, 0));
+        sendMessage(CMD_SET_FREQUENCY_BAND, band, 0);
     }
 
     /**
@@ -1050,7 +1043,7 @@
      * Send a message indicating bluetooth adapter connection state changed
      */
     public void sendBluetoothAdapterStateChange(int state) {
-        sendMessage(obtainMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0));
+        sendMessage(CMD_BLUETOOTH_ADAPTER_STATE_CHANGE, state, 0);
     }
 
     /**
@@ -1114,7 +1107,7 @@
         pw.println("mLastBssid " + mLastBssid);
         pw.println("mLastNetworkId " + mLastNetworkId);
         pw.println("mReconnectCount " + mReconnectCount);
-        pw.println("mIsScanMode " + mIsScanMode);
+        pw.println("mOperationalMode " + mOperationalMode);
         pw.println("mUserWantsSuspendOpt " + mUserWantsSuspendOpt);
         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
         pw.println("Supplicant status " + mWifiNative.status());
@@ -1136,11 +1129,11 @@
         if (screenOn) enableAllNetworks();
         if (mUserWantsSuspendOpt.get()) {
             if (screenOn) {
-                sendMessage(obtainMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0));
+                sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0);
             } else {
                 //Allow 2s for suspend optimizations to be set
                 mSuspendWakeLock.acquire(2000);
-                sendMessage(obtainMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0));
+                sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 1, 0);
             }
         }
         mScreenBroadcastReceived.set(true);
@@ -1684,12 +1677,12 @@
         setNetworkDetailedState(DetailedState.DISCONNECTED);
         mWifiConfigStore.updateStatus(mLastNetworkId, DetailedState.DISCONNECTED);
 
-        /* send event to CM & network change broadcast */
-        sendNetworkStateChangeBroadcast(mLastBssid);
-
         /* Clear network properties */
         mLinkProperties.clear();
 
+        /* send event to CM & network change broadcast */
+        sendNetworkStateChangeBroadcast(mLastBssid);
+
         /* Clear IP settings if the network used DHCP */
         if (!mWifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
             mWifiConfigStore.clearLinkProperties(mLastNetworkId);
@@ -1914,7 +1907,7 @@
                 case WifiMonitor.WPS_OVERLAP_EVENT:
                 case CMD_BLACKLIST_NETWORK:
                 case CMD_CLEAR_BLACKLIST:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_RSSI_POLL:
@@ -1929,6 +1922,7 @@
                 case WifiWatchdogStateMachine.POOR_LINK_DETECTED:
                 case WifiWatchdogStateMachine.GOOD_LINK_DETECTED:
                 case CMD_NO_NETWORKS_PERIODIC_SCAN:
+                case CMD_DISABLE_P2P_RSP:
                     break;
                 case DhcpStateMachine.CMD_ON_QUIT:
                     mDhcpStateMachine = null;
@@ -1942,8 +1936,8 @@
                     }
                     break;
                 case WifiMonitor.DRIVER_HUNG_EVENT:
-                    setWifiEnabled(false);
-                    setWifiEnabled(true);
+                    setSupplicantRunning(false);
+                    setSupplicantRunning(true);
                     break;
                 case WifiManager.CONNECT_NETWORK:
                     replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
@@ -2143,7 +2137,7 @@
                 case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2160,8 +2154,6 @@
     class SupplicantStartedState extends State {
         @Override
         public void enter() {
-            /* Initialize for connect mode operation at start */
-            mIsScanMode = false;
             /* Wifi is available as long as we have a connection to supplicant */
             mNetworkInfo.setIsAvailable(true);
 
@@ -2176,7 +2168,6 @@
         }
         @Override
         public boolean processMessage(Message message) {
-            WifiConfiguration config;
             switch(message.what) {
                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
                     if (mP2pSupported) {
@@ -2206,87 +2197,13 @@
                     boolean ok = mWifiNative.ping();
                     replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
                     break;
-                case CMD_ADD_OR_UPDATE_NETWORK:
-                    config = (WifiConfiguration) message.obj;
-                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
-                            mWifiConfigStore.addOrUpdateNetwork(config));
-                    break;
-                case CMD_REMOVE_NETWORK:
-                    ok = mWifiConfigStore.removeNetwork(message.arg1);
-                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
-                    break;
-                case CMD_ENABLE_NETWORK:
-                    ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
-                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
-                    break;
-                case CMD_ENABLE_ALL_NETWORKS:
-                    long time =  android.os.SystemClock.elapsedRealtime();
-                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
-                        mWifiConfigStore.enableAllNetworks();
-                        mLastEnableAllNetworksTime = time;
-                    }
-                    break;
-                case WifiManager.DISABLE_NETWORK:
-                    if (mWifiConfigStore.disableNetwork(message.arg1,
-                            WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) {
-                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
-                    } else {
-                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
-                                WifiManager.ERROR);
-                    }
-                    break;
-                case CMD_BLACKLIST_NETWORK:
-                    mWifiNative.addToBlacklist((String)message.obj);
-                    break;
-                case CMD_CLEAR_BLACKLIST:
-                    mWifiNative.clearBlacklist();
-                    break;
-                case CMD_SAVE_CONFIG:
-                    ok = mWifiConfigStore.saveConfig();
-                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
-
-                    // Inform the backup manager about a data change
-                    IBackupManager ibm = IBackupManager.Stub.asInterface(
-                            ServiceManager.getService(Context.BACKUP_SERVICE));
-                    if (ibm != null) {
-                        try {
-                            ibm.dataChanged("com.android.providers.settings");
-                        } catch (Exception e) {
-                            // Try again later
-                        }
-                    }
-                    break;
-                case CMD_GET_CONFIGURED_NETWORKS:
-                    replyToMessage(message, message.what,
-                            mWifiConfigStore.getConfiguredNetworks());
-                    break;
                     /* Cannot start soft AP while in client mode */
                 case CMD_START_AP:
                     loge("Failed to start soft AP with a running supplicant");
                     setWifiApState(WIFI_AP_STATE_FAILED);
                     break;
-                case CMD_SET_SCAN_MODE:
-                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);
-                    break;
-                case WifiManager.SAVE_NETWORK:
-                    config = (WifiConfiguration) message.obj;
-                    NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
-                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
-                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
-                    } else {
-                        loge("Failed to save network");
-                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
-                                WifiManager.ERROR);
-                    }
-                    break;
-                case WifiManager.FORGET_NETWORK:
-                    if (mWifiConfigStore.forgetNetwork(message.arg1)) {
-                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
-                    } else {
-                        loge("Failed to forget network");
-                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
-                                WifiManager.ERROR);
-                    }
+                case CMD_SET_OPERATIONAL_MODE:
+                    mOperationalMode = message.arg1;
                     break;
                 default:
                     return NOT_HANDLED;
@@ -2344,7 +2261,7 @@
                 case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2452,7 +2369,7 @@
                 mWifiNative.stopFilteringMulticastV4Packets();
             }
 
-            if (mIsScanMode) {
+            if (mOperationalMode != CONNECT_MODE) {
                 mWifiNative.disconnect();
                 transitionTo(mScanModeState);
             } else {
@@ -2510,8 +2427,8 @@
                 case CMD_STOP_DRIVER:
                     int mode = message.arg1;
 
-                    /* Already doing a delayed stop && not in ecm state */
-                    if (mInDelayedStop && mode != IN_ECM_STATE) {
+                    /* Already doing a delayed stop */
+                    if (mInDelayedStop) {
                         if (DBG) log("Already in delayed stop");
                         break;
                     }
@@ -2519,20 +2436,15 @@
                     mDelayedStopCounter++;
                     if (DBG) log("Delayed stop message " + mDelayedStopCounter);
 
-                    if (mode == IN_ECM_STATE) {
-                        /* send a shut down immediately */
-                        sendMessage(obtainMessage(CMD_DELAYED_STOP_DRIVER, mDelayedStopCounter, 0));
-                    } else {
-                        /* send regular delayed shut down */
-                        Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
-                        driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
-                        mDriverStopIntent = PendingIntent.getBroadcast(mContext,
-                                DRIVER_STOP_REQUEST, driverStopIntent,
-                                PendingIntent.FLAG_UPDATE_CURRENT);
+                    /* send regular delayed shut down */
+                    Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null);
+                    driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter);
+                    mDriverStopIntent = PendingIntent.getBroadcast(mContext,
+                            DRIVER_STOP_REQUEST, driverStopIntent,
+                            PendingIntent.FLAG_UPDATE_CURRENT);
 
-                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
-                                + mDriverStopDelayMs, mDriverStopIntent);
-                    }
+                    mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+                            + mDriverStopDelayMs, mDriverStopIntent);
                     break;
                 case CMD_START_DRIVER:
                     if (mInDelayedStop) {
@@ -2638,7 +2550,7 @@
                 case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -2713,30 +2625,42 @@
     }
 
     class ScanModeState extends State {
+        private int mLastOperationMode;
+        @Override
+        public void enter() {
+            mWifiConfigStore.disableAllNetworks();
+            mLastOperationMode = mOperationalMode;
+            if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
+                mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ);
+                setWifiState(WIFI_STATE_DISABLED);
+            }
+        }
+        @Override
+        public void exit() {
+            if (mLastOperationMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
+                setWifiState(WIFI_STATE_ENABLED);
+                mWifiP2pChannel.sendMessage(CMD_ENABLE_P2P);
+            }
+            mWifiConfigStore.enableAllNetworks();
+            mWifiNative.reconnect();
+        }
         @Override
         public boolean processMessage(Message message) {
             switch(message.what) {
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
-                        /* Ignore */
-                        return HANDLED;
-                    } else {
-                        mWifiNative.reconnect();
-                        mIsScanMode = false;
+                case CMD_SET_OPERATIONAL_MODE:
+                    if (message.arg1 == CONNECT_MODE) {
+                        mOperationalMode = CONNECT_MODE;
                         transitionTo(mDisconnectedState);
+                    } else {
+                        // Nothing to do
+                        return HANDLED;
                     }
                     break;
+                // Handle scan. All the connection related commands are
+                // handled only in ConnectModeState
                 case CMD_START_SCAN:
                     startScanNative(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP);
                     break;
-                    /* Ignore */
-                case CMD_DISCONNECT:
-                case CMD_RECONNECT:
-                case CMD_REASSOCIATE:
-                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
-                case WifiMonitor.NETWORK_CONNECTION_EVENT:
-                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
-                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -2747,7 +2671,8 @@
     class ConnectModeState extends State {
         @Override
         public boolean processMessage(Message message) {
-            StateChangeResult stateChangeResult;
+            WifiConfiguration config;
+            boolean ok;
             switch(message.what) {
                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
                     mSupplicantStateTracker.sendMessage(WifiMonitor.AUTHENTICATION_FAILURE_EVENT);
@@ -2787,6 +2712,60 @@
                         mTemporarilyDisconnectWifi = false;
                     }
                     break;
+                case CMD_ADD_OR_UPDATE_NETWORK:
+                    config = (WifiConfiguration) message.obj;
+                    replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,
+                            mWifiConfigStore.addOrUpdateNetwork(config));
+                    break;
+                case CMD_REMOVE_NETWORK:
+                    ok = mWifiConfigStore.removeNetwork(message.arg1);
+                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
+                    break;
+                case CMD_ENABLE_NETWORK:
+                    ok = mWifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);
+                    replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);
+                    break;
+                case CMD_ENABLE_ALL_NETWORKS:
+                    long time =  android.os.SystemClock.elapsedRealtime();
+                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {
+                        mWifiConfigStore.enableAllNetworks();
+                        mLastEnableAllNetworksTime = time;
+                    }
+                    break;
+                case WifiManager.DISABLE_NETWORK:
+                    if (mWifiConfigStore.disableNetwork(message.arg1,
+                            WifiConfiguration.DISABLED_UNKNOWN_REASON) == true) {
+                        replyToMessage(message, WifiManager.DISABLE_NETWORK_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
+                                WifiManager.ERROR);
+                    }
+                    break;
+                case CMD_BLACKLIST_NETWORK:
+                    mWifiNative.addToBlacklist((String)message.obj);
+                    break;
+                case CMD_CLEAR_BLACKLIST:
+                    mWifiNative.clearBlacklist();
+                    break;
+                case CMD_SAVE_CONFIG:
+                    ok = mWifiConfigStore.saveConfig();
+                    replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);
+
+                    // Inform the backup manager about a data change
+                    IBackupManager ibm = IBackupManager.Stub.asInterface(
+                            ServiceManager.getService(Context.BACKUP_SERVICE));
+                    if (ibm != null) {
+                        try {
+                            ibm.dataChanged("com.android.providers.settings");
+                        } catch (Exception e) {
+                            // Try again later
+                        }
+                    }
+                    break;
+                case CMD_GET_CONFIGURED_NETWORKS:
+                    replyToMessage(message, message.what,
+                            mWifiConfigStore.getConfiguredNetworks());
+                    break;
                     /* Do a redundant disconnect without transition */
                 case CMD_DISCONNECT:
                     mWifiNative.disconnect();
@@ -2804,7 +2783,7 @@
                      * For an existing network, a network id is passed
                      */
                     int netId = message.arg1;
-                    WifiConfiguration config = (WifiConfiguration) message.obj;
+                    config = (WifiConfiguration) message.obj;
 
                     /* Save the network config */
                     if (config != null) {
@@ -2826,26 +2805,46 @@
                         break;
                     }
                     break;
+                case WifiManager.SAVE_NETWORK:
+                    config = (WifiConfiguration) message.obj;
+                    NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
+                    if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
+                        replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
+                    } else {
+                        loge("Failed to save network");
+                        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
+                                WifiManager.ERROR);
+                    }
+                    break;
+                case WifiManager.FORGET_NETWORK:
+                    if (mWifiConfigStore.forgetNetwork(message.arg1)) {
+                        replyToMessage(message, WifiManager.FORGET_NETWORK_SUCCEEDED);
+                    } else {
+                        loge("Failed to forget network");
+                        replyToMessage(message, WifiManager.FORGET_NETWORK_FAILED,
+                                WifiManager.ERROR);
+                    }
+                    break;
                 case WifiManager.START_WPS:
                     WpsInfo wpsInfo = (WpsInfo) message.obj;
-                    WpsResult result;
+                    WpsResult wpsResult;
                     switch (wpsInfo.setup) {
                         case WpsInfo.PBC:
-                            result = mWifiConfigStore.startWpsPbc(wpsInfo);
+                            wpsResult = mWifiConfigStore.startWpsPbc(wpsInfo);
                             break;
                         case WpsInfo.KEYPAD:
-                            result = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
+                            wpsResult = mWifiConfigStore.startWpsWithPinFromAccessPoint(wpsInfo);
                             break;
                         case WpsInfo.DISPLAY:
-                            result = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
+                            wpsResult = mWifiConfigStore.startWpsWithPinFromDevice(wpsInfo);
                             break;
                         default:
-                            result = new WpsResult(Status.FAILURE);
+                            wpsResult = new WpsResult(Status.FAILURE);
                             loge("Invalid setup for WPS");
                             break;
                     }
-                    if (result.status == Status.SUCCESS) {
-                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, result);
+                    if (wpsResult.status == Status.SUCCESS) {
+                        replyToMessage(message, WifiManager.START_WPS_SUCCEEDED, wpsResult);
                         transitionTo(mWpsRunningState);
                     } else {
                         loge("Failed to start WPS with config " + wpsInfo.toString());
@@ -2881,7 +2880,7 @@
         public void enter() {
             mRssiPollToken++;
             if (mEnableRssiPolling) {
-                sendMessage(obtainMessage(CMD_RSSI_POLL, mRssiPollToken, 0));
+                sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
             }
         }
 
@@ -2915,8 +2914,8 @@
                         transitionTo(mDisconnectingState);
                     }
                     break;
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
+                case CMD_SET_OPERATIONAL_MODE:
+                    if (message.arg1 != CONNECT_MODE) {
                         sendMessage(CMD_DISCONNECT);
                         deferMessage(message);
                     }
@@ -3152,8 +3151,8 @@
         @Override
         public boolean processMessage(Message message) {
             switch (message.what) {
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
+                case CMD_SET_OPERATIONAL_MODE:
+                    if (message.arg1 != CONNECT_MODE) {
                         deferMessage(message);
                     }
                     break;
@@ -3259,11 +3258,9 @@
                                 ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
                     ret = NOT_HANDLED;
                     break;
-                case CMD_SET_SCAN_MODE:
-                    if (message.arg1 == SCAN_ONLY_MODE) {
-                        //Supplicant disconnect to prevent further connects
-                        mWifiNative.disconnect();
-                        mIsScanMode = true;
+                case CMD_SET_OPERATIONAL_MODE:
+                    if (message.arg1 != CONNECT_MODE) {
+                        mOperationalMode = message.arg1;
                         transitionTo(mScanModeState);
                     }
                     break;
@@ -3319,9 +3316,14 @@
                     }
                 case CMD_RECONNECT:
                 case CMD_REASSOCIATE:
-                    // Drop a third party reconnect/reassociate if we are
-                    // tempoarily disconnected for p2p
-                    if (mTemporarilyDisconnectWifi) ret = NOT_HANDLED;
+                    if (mTemporarilyDisconnectWifi) {
+                        // Drop a third party reconnect/reassociate if STA is
+                        // temporarily disconnected for p2p
+                        break;
+                    } else {
+                        // ConnectModeState handles it
+                        ret = NOT_HANDLED;
+                    }
                     break;
                 default:
                     ret = NOT_HANDLED;
@@ -3391,7 +3393,7 @@
                  * or put the state machine out of connect mode
                  */
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case WifiManager.CONNECT_NETWORK:
                 case CMD_ENABLE_NETWORK:
                 case CMD_RECONNECT:
@@ -3454,7 +3456,7 @@
                 case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3542,7 +3544,8 @@
                     if (message.arg1 == mTetherToken) {
                         loge("Failed to get tether update, shutdown soft access point");
                         transitionTo(mSoftApStartedState);
-                        sendMessage(CMD_STOP_AP);
+                        // Needs to be first thing handled
+                        sendMessageAtFrontOfQueue(CMD_STOP_AP);
                     }
                     break;
                 case CMD_START_SUPPLICANT:
@@ -3551,7 +3554,7 @@
                 case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
@@ -3573,7 +3576,7 @@
                     TetherStateChange stateChange = (TetherStateChange) message.obj;
                     if (!isWifiTethered(stateChange.active)) {
                         loge("Tethering reports wifi as untethered!, shut down soft Ap");
-                        setWifiApEnabled(null, false);
+                        setHostApRunning(null, false);
                     }
                     return HANDLED;
                 case CMD_STOP_AP:
@@ -3581,6 +3584,8 @@
                     setWifiApState(WIFI_AP_STATE_DISABLING);
                     stopTethering();
                     transitionTo(mUntetheringState);
+                    // More work to do after untethering
+                    deferMessage(message);
                     break;
                 default:
                     return NOT_HANDLED;
@@ -3607,13 +3612,11 @@
                     if (isWifiTethered(stateChange.active)) break;
 
                     transitionTo(mSoftApStartedState);
-                    sendMessage(CMD_STOP_AP);
                     break;
                 case CMD_TETHER_NOTIFICATION_TIMED_OUT:
                     if (message.arg1 == mTetherToken) {
                         loge("Failed to get tether update, force stop access point");
                         transitionTo(mSoftApStartedState);
-                        sendMessage(CMD_STOP_AP);
                     }
                     break;
                 case CMD_START_SUPPLICANT:
@@ -3622,7 +3625,7 @@
                 case CMD_STOP_AP:
                 case CMD_START_DRIVER:
                 case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
+                case CMD_SET_OPERATIONAL_MODE:
                 case CMD_SET_COUNTRY_CODE:
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 55ea34f..cf75381 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -27,6 +27,7 @@
 import android.net.NetworkStateTracker;
 import android.os.Handler;
 import android.os.Message;
+import android.os.Messenger;
 import android.util.Slog;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -252,4 +253,19 @@
     public void setDependencyMet(boolean met) {
         // not supported on this network
     }
+
+    @Override
+    public void addStackedLink(LinkProperties link) {
+        mLinkProperties.addStackedLink(link);
+    }
+
+    @Override
+    public void removeStackedLink(LinkProperties link) {
+        mLinkProperties.removeStackedLink(link);
+    }
+
+    @Override
+    public void supplyMessenger(Messenger messenger) {
+        // not supported on this network
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 53e6b51..eb47a4a 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -587,8 +587,9 @@
                     break;
 
                 case EVENT_WIFI_RADIO_STATE_CHANGE:
-                    if ((Integer) msg.obj == WifiManager.WIFI_STATE_DISABLING)
+                    if (msg.arg1 == WifiManager.WIFI_STATE_DISABLING) {
                         transitionTo(mNotConnectedState);
+                    }
                     break;
 
                 default:
diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
index 381a450..1c9c40d 100644
--- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
+++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl
@@ -26,5 +26,6 @@
 interface IWifiP2pManager
 {
     Messenger getMessenger();
+    void setMiracastMode(int mode);
 }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 2e80064..737ab91 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1258,6 +1258,21 @@
         c.mAsyncChannel.sendMessage(REQUEST_PERSISTENT_GROUP_INFO, 0, c.putListener(listener));
     }
 
+    /** @hide */
+    public static final int MIRACAST_DISABLED = 0;
+    /** @hide */
+    public static final int MIRACAST_SOURCE   = 1;
+    /** @hide */
+    public static final int MIRACAST_SINK     = 2;
+    /** Internal use only @hide */
+    public void setMiracastMode(int mode) {
+        try {
+            mService.setMiracastMode(mode);
+        } catch(RemoteException e) {
+           // ignore
+        }
+    }
+
     /**
      * Get a reference to WifiP2pService handler. This is used to establish
      * an AsyncChannel communication with WifiService
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index e6a1df1..447ddb0 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -164,6 +164,8 @@
     public static final int DISCONNECT_WIFI_REQUEST         =   BASE + 12;
     public static final int DISCONNECT_WIFI_RESPONSE        =   BASE + 13;
 
+    public static final int SET_MIRACAST_MODE               =   BASE + 14;
+
     private final boolean mP2pSupported;
 
     private WifiP2pDevice mThisDevice = new WifiP2pDevice();
@@ -310,6 +312,12 @@
                 "WifiP2pService");
     }
 
+    private void enforceConnectivityInternalPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+                "WifiP2pService");
+    }
+
     /**
      * Get a reference to handler. This is used by a client to establish
      * an AsyncChannel communication with WifiP2pService
@@ -320,6 +328,20 @@
         return new Messenger(mP2pStateMachine.getHandler());
     }
 
+    /** This is used to provide information to drivers to optimize performance depending
+     * on the current mode of operation.
+     * 0 - disabled
+     * 1 - source operation
+     * 2 - sink operation
+     *
+     * As an example, the driver could reduce the channel dwell time during scanning
+     * when acting as a source or sink to minimize impact on miracast.
+     */
+    public void setMiracastMode(int mode) {
+        enforceConnectivityInternalPermission();
+        mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode);
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -572,6 +594,7 @@
                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
                 case DhcpStateMachine.CMD_ON_QUIT:
                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
+                case SET_MIRACAST_MODE:
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
                     // Enable is lazy and has no response
@@ -878,7 +901,7 @@
                         sendPeersChangedBroadcast();
                     }
                     break;
-               case WifiP2pManager.ADD_LOCAL_SERVICE:
+                case WifiP2pManager.ADD_LOCAL_SERVICE:
                     if (DBG) logd(getName() + " add service");
                     WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
                     if (addLocalService(message.replyTo, servInfo)) {
@@ -916,7 +939,7 @@
                     clearServiceRequests(message.replyTo);
                     replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
                     break;
-               case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
+                case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
                     if (DBG) logd(getName() + " receive service response");
                     List<WifiP2pServiceResponse> sdRespList =
                         (List<WifiP2pServiceResponse>) message.obj;
@@ -927,13 +950,16 @@
                         sendServiceResponse(resp);
                     }
                     break;
-               case WifiP2pManager.DELETE_PERSISTENT_GROUP:
+                case WifiP2pManager.DELETE_PERSISTENT_GROUP:
                    if (DBG) logd(getName() + " delete persistent group");
                    mGroups.remove(message.arg1);
                    replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
                    break;
+                case SET_MIRACAST_MODE:
+                    mWifiNative.setMiracastMode(message.arg1);
+                    break;
                 default:
-                    return NOT_HANDLED;
+                   return NOT_HANDLED;
             }
             return HANDLED;
         }