Merge "Add new error code for Debug Context work." into jb-mr2-dev
diff --git a/Android.mk b/Android.mk
index 8115472..bd88877 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,7 @@
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
 	core/java/android/hardware/location/IGeofenceHardware.aidl \
 	core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
+	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
diff --git a/api/current.txt b/api/current.txt
index 5a33193..6769433 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37,8 +37,6 @@
     field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
     field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
     field public static final java.lang.String CAMERA = "android.permission.CAMERA";
-    field public static final java.lang.String CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = "android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
-    field public static final java.lang.String CAN_REQUEST_TOUCH_EXPLORATION_MODE = "android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE";
     field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
     field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -322,6 +320,9 @@
     field public static final int cacheColorHint = 16843009; // 0x1010101
     field public static final int calendarViewShown = 16843596; // 0x101034c
     field public static final int calendarViewStyle = 16843613; // 0x101035d
+    field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+    field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
+    field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final deprecated int capitalize = 16843113; // 0x1010169
@@ -1703,7 +1704,6 @@
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
-    field public static final int Theme_Black_NoTitleBar_Overscan = 16974303; // 0x10301df
     field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
     field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
     field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
@@ -1722,11 +1722,11 @@
     field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
     field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
     field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
-    field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974307; // 0x10301e3
+    field public static final int Theme_DeviceDefault_Light_NoActionBar_Overscan = 16974304; // 0x10301e0
     field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
     field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
     field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
-    field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974306; // 0x10301e2
+    field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974303; // 0x10301df
     field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
     field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
     field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
@@ -1749,11 +1749,11 @@
     field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
     field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
     field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
-    field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974305; // 0x10301e1
+    field public static final int Theme_Holo_Light_NoActionBar_Overscan = 16974302; // 0x10301de
     field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
     field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
     field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
-    field public static final int Theme_Holo_NoActionBar_Overscan = 16974304; // 0x10301e0
+    field public static final int Theme_Holo_NoActionBar_Overscan = 16974301; // 0x10301dd
     field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
     field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
     field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
@@ -1761,14 +1761,12 @@
     field public static final int Theme_Light = 16973836; // 0x103000c
     field public static final int Theme_Light_NoTitleBar = 16973837; // 0x103000d
     field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
-    field public static final int Theme_Light_NoTitleBar_Overscan = 16974302; // 0x10301de
     field public static final int Theme_Light_Panel = 16973914; // 0x103005a
     field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
     field public static final int Theme_NoDisplay = 16973909; // 0x1030055
     field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
     field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
-    field public static final int Theme_NoTitleBar_Overscan = 16974301; // 0x10301dd
     field public static final int Theme_Panel = 16973913; // 0x1030059
     field public static final int Theme_Translucent = 16973839; // 0x103000f
     field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
@@ -2107,16 +2105,22 @@
 
   public class AccessibilityServiceInfo implements android.os.Parcelable {
     ctor public AccessibilityServiceInfo();
+    method public static java.lang.String capabilityToString(int);
     method public int describeContents();
     method public static java.lang.String feedbackTypeToString(int);
     method public static java.lang.String flagToString(int);
-    method public boolean getCanRetrieveWindowContent();
+    method public deprecated boolean getCanRetrieveWindowContent();
+    method public int getCapabilities();
     method public deprecated java.lang.String getDescription();
     method public java.lang.String getId();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DEFAULT = 1; // 0x1
     field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
@@ -2129,6 +2133,7 @@
     field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
     field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
     field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
     field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
     field public int eventTypes;
     field public int feedbackType;
@@ -2193,6 +2198,7 @@
     method public android.accounts.Account[] getAccounts();
     method public android.accounts.Account[] getAccountsByType(java.lang.String);
     method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
+    method public android.accounts.Account[] getAccountsByTypeForPackage(java.lang.String, java.lang.String);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public deprecated android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
@@ -2306,28 +2312,23 @@
 
 package android.animation {
 
-  public abstract interface Animatable {
-    method public abstract long getDuration();
-    method public abstract android.animation.TimeInterpolator getInterpolator();
-    method public abstract long getStartDelay();
-    method public abstract android.animation.Animatable setDuration(long);
-    method public abstract void setInterpolator(android.animation.TimeInterpolator);
-    method public abstract void setStartDelay(long);
-  }
-
-  public abstract class Animator implements android.animation.Animatable java.lang.Cloneable {
+  public abstract class Animator implements java.lang.Cloneable {
     ctor public Animator();
     method public void addListener(android.animation.Animator.AnimatorListener);
     method public void cancel();
     method public android.animation.Animator clone();
     method public void end();
+    method public abstract long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
+    method public abstract long getStartDelay();
     method public abstract boolean isRunning();
     method public boolean isStarted();
     method public void removeAllListeners();
     method public void removeListener(android.animation.Animator.AnimatorListener);
     method public abstract android.animation.Animator setDuration(long);
+    method public abstract void setInterpolator(android.animation.TimeInterpolator);
+    method public abstract void setStartDelay(long);
     method public void setTarget(java.lang.Object);
     method public void setupEndValues();
     method public void setupStartValues();
@@ -3122,9 +3123,9 @@
     method public void onTerminate();
     method public void onTrimMemory(int);
     method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
-    method public void registerOnProvideAssistData(android.app.Application.OnProvideAssistData);
+    method public void registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
     method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
-    method public void unregisterOnProvideAssistData(android.app.Application.OnProvideAssistData);
+    method public void unregisterOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener);
   }
 
   public static abstract interface Application.ActivityLifecycleCallbacks {
@@ -3137,7 +3138,7 @@
     method public abstract void onActivityStopped(android.app.Activity);
   }
 
-  public static abstract interface Application.OnProvideAssistData {
+  public static abstract interface Application.OnProvideAssistDataListener {
     method public abstract void onProvideAssistData(android.app.Activity, android.os.Bundle);
   }
 
@@ -4358,7 +4359,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 boolean isDeviceOwnerApp(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
@@ -4633,13 +4634,11 @@
     method public boolean isEnabled();
     method public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
     method public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(java.lang.String, java.util.UUID) throws java.io.IOException;
-    method public boolean registerCallback(android.bluetooth.BluetoothAdapterCallback);
     method public boolean setName(java.lang.String);
     method public boolean startDiscovery();
-    method public boolean startLeScan();
-    method public boolean startLeScan(java.util.UUID[]);
-    method public void stopLeScan();
-    method public boolean unRegisterCallback(android.bluetooth.BluetoothAdapterCallback);
+    method public boolean startLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
+    method public boolean startLeScan(java.util.UUID[], android.bluetooth.BluetoothAdapter.LeScanCallback);
+    method public void stopLeScan(android.bluetooth.BluetoothAdapter.LeScanCallback);
     field public static final java.lang.String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
@@ -4670,12 +4669,8 @@
     field public static final int STATE_TURNING_ON = 11; // 0xb
   }
 
-  public abstract class BluetoothAdapterCallback {
-    ctor public BluetoothAdapterCallback();
-    method public void onCallbackRegistration(int);
-    method public void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
-    field public static final int CALLBACK_REGISTERED = 0; // 0x0
-    field public static final int CALLBACK_REGISTRATION_FAILURE = 1; // 0x1
+  public static abstract interface BluetoothAdapter.LeScanCallback {
+    method public abstract void onLeScan(android.bluetooth.BluetoothDevice, int, byte[]);
   }
 
   public class BluetoothAssignedNumbers {
@@ -5618,7 +5613,6 @@
     method public abstract java.lang.String[] fileList();
     method public abstract android.content.Context getApplicationContext();
     method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
-    method public java.util.List<android.content.RestrictionEntry> getApplicationRestrictions();
     method public abstract android.content.res.AssetManager getAssets();
     method public abstract java.io.File getCacheDir();
     method public abstract java.lang.ClassLoader getClassLoader();
@@ -6205,8 +6199,9 @@
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
     field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
-    field public static final java.lang.String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+    field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
     field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
+    field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
     field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
     field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
@@ -10476,13 +10471,14 @@
 package android.hardware.location {
 
   public final class GeofenceHardware {
-    method public boolean addCircularFence(int, double, double, double, int, int, int, int, int, android.hardware.location.GeofenceHardwareCallback);
-    method public int[] getMonitoringTypesAndStatus();
+    method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
+    method public int[] getMonitoringTypes();
+    method public int getStatusOfMonitoringType(int);
     method public boolean pauseGeofence(int, int);
-    method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+    method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
     method public boolean removeGeofence(int, int);
     method public boolean resumeGeofence(int, int, int);
-    method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareCallback);
+    method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
     field public static final int GEOFENCE_ENTERED = 1; // 0x1
     field public static final int GEOFENCE_ERROR_ID_EXISTS = 2; // 0x2
     field public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3; // 0x3
@@ -10501,13 +10497,33 @@
   public abstract class GeofenceHardwareCallback {
     ctor public GeofenceHardwareCallback();
     method public void onGeofenceAdd(int, int);
-    method public void onGeofenceChange(int, int, android.location.Location, long, int);
     method public void onGeofencePause(int, int);
     method public void onGeofenceRemove(int, int);
     method public void onGeofenceResume(int, int);
+    method public void onGeofenceTransition(int, int, android.location.Location, long, int);
+  }
+
+  public abstract class GeofenceHardwareMonitorCallback {
+    ctor public GeofenceHardwareMonitorCallback();
     method public void onMonitoringSystemChange(int, boolean, android.location.Location);
   }
 
+  public final class GeofenceHardwareRequest {
+    ctor public GeofenceHardwareRequest();
+    method public static android.hardware.location.GeofenceHardwareRequest createCircularGeofence(double, double, double);
+    method public int getLastTransition();
+    method public double getLatitude();
+    method public double getLongitude();
+    method public int getMonitorTransitions();
+    method public int getNotificationResponsiveness();
+    method public double getRadius();
+    method public int getUnknownTimer();
+    method public void setLastTransition(int);
+    method public void setMonitorTransitions(int);
+    method public void setNotificationResponsiveness(int);
+    method public void setUnknownTimer(int);
+  }
+
 }
 
 package android.hardware.usb {
@@ -10579,11 +10595,11 @@
   }
 
   public class UsbDeviceConnection {
-    method public deprecated int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
+    method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int);
     method public int bulkTransfer(android.hardware.usb.UsbEndpoint, byte[], int, int, int);
     method public boolean claimInterface(android.hardware.usb.UsbInterface, boolean);
     method public void close();
-    method public deprecated int controlTransfer(int, int, int, int, byte[], int, int);
+    method public int controlTransfer(int, int, int, int, byte[], int, int);
     method public int controlTransfer(int, int, int, int, byte[], int, int, int);
     method public int getFileDescriptor();
     method public byte[] getRawDescriptors();
@@ -11801,6 +11817,66 @@
     ctor public MediaCryptoException(java.lang.String);
   }
 
+  public final class MediaDrm {
+    ctor public MediaDrm(java.util.UUID) throws android.media.MediaDrmException;
+    method public void closeSession(byte[]);
+    method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
+    method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>);
+    method public byte[] getPropertyByteArray(java.lang.String);
+    method public java.lang.String getPropertyString(java.lang.String);
+    method public android.media.MediaDrm.ProvisionRequest getProvisionRequest();
+    method public java.util.List<byte[]> getSecureStops();
+    method public static final boolean isCryptoSchemeSupported(java.util.UUID);
+    method public byte[] openSession();
+    method public byte[] provideKeyResponse(byte[], byte[]);
+    method public void provideProvisionResponse(byte[]);
+    method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
+    method public final void release();
+    method public void releaseSecureStops(byte[]);
+    method public void removeKeys(byte[]);
+    method public void restoreKeys(byte[], byte[]);
+    method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
+    method public void setPropertyByteArray(java.lang.String, byte[]);
+    method public void setPropertyString(java.lang.String, java.lang.String);
+    field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
+    field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
+    field public static final int EVENT_PROVISION_REQUIRED = 1; // 0x1
+    field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+    field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
+    field public static final int KEY_TYPE_RELEASE = 3; // 0x3
+    field public static final int KEY_TYPE_STREAMING = 1; // 0x1
+    field public static final java.lang.String PROPERTY_ALGORITHMS = "algorithms";
+    field public static final java.lang.String PROPERTY_DESCRIPTION = "description";
+    field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
+    field public static final java.lang.String PROPERTY_VENDOR = "vendor";
+    field public static final java.lang.String PROPERTY_VERSION = "version";
+  }
+
+  public final class MediaDrm.CryptoSession {
+    method public byte[] decrypt(byte[], byte[], byte[]);
+    method public byte[] encrypt(byte[], byte[], byte[]);
+    method public byte[] sign(byte[], byte[]);
+    method public boolean verify(byte[], byte[], byte[]);
+  }
+
+  public static final class MediaDrm.KeyRequest {
+    method public byte[] getData();
+    method public java.lang.String getDefaultUrl();
+  }
+
+  public static abstract interface MediaDrm.OnEventListener {
+    method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
+  }
+
+  public static final class MediaDrm.ProvisionRequest {
+    method public byte[] getData();
+    method public java.lang.String getDefaultUrl();
+  }
+
+  public final class MediaDrmException extends java.lang.Exception {
+    ctor public MediaDrmException(java.lang.String);
+  }
+
   public final class MediaExtractor {
     ctor public MediaExtractor();
     method public boolean advance();
@@ -13856,8 +13932,11 @@
     ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
     method public int describeContents();
     method public java.lang.String getAnonymousIdentity();
+    method public java.security.cert.X509Certificate getCaCertificate();
+    method public java.security.cert.X509Certificate getClientCertificate();
     method public int getEapMethod();
     method public java.lang.String getIdentity();
+    method public java.lang.String getPassword();
     method public int getPhase2Method();
     method public java.lang.String getSubjectMatch();
     method public void setAnonymousIdentity(java.lang.String);
@@ -13873,7 +13952,6 @@
   }
 
   public static final class WifiEnterpriseConfig.Eap {
-    ctor public WifiEnterpriseConfig.Eap();
     field public static final int NONE = -1; // 0xffffffff
     field public static final int PEAP = 0; // 0x0
     field public static final int PWD = 3; // 0x3
@@ -13882,7 +13960,6 @@
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
-    ctor public WifiEnterpriseConfig.Phase2();
     field public static final int GTC = 4; // 0x4
     field public static final int MSCHAP = 2; // 0x2
     field public static final int MSCHAPV2 = 3; // 0x3
@@ -13921,7 +13998,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 isScanAlwaysAvailable();
     method public boolean isWifiEnabled();
     method public boolean pingSupplicant();
     method public boolean reassociate();
@@ -17046,6 +17123,7 @@
     method public int getThreadId();
     method protected void onLooperPrepared();
     method public boolean quit();
+    method public boolean quitSafely();
   }
 
   public abstract interface IBinder {
@@ -17086,6 +17164,7 @@
     method public static void prepare();
     method public static void prepareMainLooper();
     method public void quit();
+    method public void quitSafely();
     method public void setMessageLogging(android.util.Printer);
   }
 
@@ -17446,16 +17525,17 @@
 
   public class StatFs {
     ctor public StatFs(java.lang.String);
-    method public int getAvailableBlocks();
+    method public deprecated int getAvailableBlocks();
     method public long getAvailableBlocksLong();
     method public long getAvailableBytes();
-    method public int getBlockCount();
+    method public deprecated int getBlockCount();
     method public long getBlockCountLong();
-    method public int getBlockSize();
+    method public deprecated int getBlockSize();
     method public long getBlockSizeLong();
-    method public int getFreeBlocks();
+    method public deprecated int getFreeBlocks();
     method public long getFreeBlocksLong();
     method public long getFreeBytes();
+    method public long getTotalBytes();
     method public void restat(java.lang.String);
   }
 
@@ -17556,7 +17636,7 @@
   }
 
   public class UserManager {
-    method public static synchronized android.os.UserManager get(android.content.Context);
+    method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
     method public android.os.UserHandle getUserForSerialNumber(long);
@@ -20219,7 +20299,6 @@
     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 setIoInputNotificationHandler(android.renderscript.Allocation.IoInputNotifier);
     method public void setSurface(android.view.Surface);
     method public void syncAll(int);
     field public static final int USAGE_GRAPHICS_CONSTANTS = 8; // 0x8
@@ -20232,10 +20311,6 @@
     field public static final int USAGE_SHARED = 128; // 0x80
   }
 
-  public static abstract interface Allocation.IoInputNotifier {
-    method public abstract void onBufferAvailable(android.renderscript.Allocation);
-  }
-
   public static final class Allocation.MipmapControl extends java.lang.Enum {
     method public static android.renderscript.Allocation.MipmapControl valueOf(java.lang.String);
     method public static final android.renderscript.Allocation.MipmapControl[] values();
@@ -20818,13 +20893,6 @@
     method public android.renderscript.Script.LaunchOptions setX(int, int);
     method public android.renderscript.Script.LaunchOptions setY(int, int);
     method public android.renderscript.Script.LaunchOptions setZ(int, int);
-    field protected int strategy;
-    field protected int xend;
-    field protected int xstart;
-    field protected int yend;
-    field protected int ystart;
-    field protected int zend;
-    field protected int zstart;
   }
 
   public class ScriptC extends android.renderscript.Script {
@@ -21050,37 +21118,6 @@
 
 package android.security {
 
-  public final class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
-    method public android.content.Context getContext();
-    method public java.util.Date getEndDate();
-    method public java.lang.String getKeystoreAlias();
-    method public java.math.BigInteger getSerialNumber();
-    method public java.util.Date getStartDate();
-    method public javax.security.auth.x500.X500Principal getSubjectDN();
-    method public boolean isEncryptionRequired();
-  }
-
-  public static final 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 setEncryptionRequired();
-    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 AndroidKeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
-    method public boolean isEncryptionRequired();
-  }
-
-  public static final class AndroidKeyStoreParameter.Builder {
-    ctor public AndroidKeyStoreParameter.Builder(android.content.Context);
-    method public android.security.AndroidKeyStoreParameter build();
-    method public android.security.AndroidKeyStoreParameter.Builder setEncryptionRequired();
-  }
-
   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);
@@ -21106,6 +21143,37 @@
     ctor public KeyChainException(java.lang.Throwable);
   }
 
+  public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public android.content.Context getContext();
+    method public java.util.Date getEndDate();
+    method public java.lang.String getKeystoreAlias();
+    method public java.math.BigInteger getSerialNumber();
+    method public java.util.Date getStartDate();
+    method public javax.security.auth.x500.X500Principal getSubjectDN();
+    method public boolean isEncryptionRequired();
+  }
+
+  public static final class KeyPairGeneratorSpec.Builder {
+    ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
+    method public android.security.KeyPairGeneratorSpec build();
+    method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
+    method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
+    method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+  }
+
+  public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
+    method public boolean isEncryptionRequired();
+  }
+
+  public static final class KeyStoreParameter.Builder {
+    ctor public KeyStoreParameter.Builder(android.content.Context);
+    method public android.security.KeyStoreParameter build();
+    method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
+  }
+
 }
 
 package android.service.dreams {
@@ -21495,7 +21563,7 @@
     method public int getLac();
     method public int getMcc();
     method public int getMnc();
-    method public int getPsc();
+    method public deprecated int getPsc();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
@@ -21511,6 +21579,17 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CellIdentityWcdma implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCid();
+    method public int getLac();
+    method public int getMcc();
+    method public int getMnc();
+    method public int getPsc();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public abstract class CellInfo implements android.os.Parcelable {
     method public int describeContents();
     method public long getTimeStamp();
@@ -21540,6 +21619,13 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
+    method public android.telephony.CellIdentityWcdma getCellIdentity();
+    method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public abstract class CellLocation {
     ctor public CellLocation();
     method public static android.telephony.CellLocation getEmpty();
@@ -21595,6 +21681,17 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean equals(java.lang.Object);
+    method public int getAsuLevel();
+    method public int getDbm();
+    method public int getLevel();
+    method public int hashCode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class NeighboringCellInfo implements android.os.Parcelable {
     ctor public deprecated NeighboringCellInfo();
     ctor public deprecated NeighboringCellInfo(int, int);
@@ -22626,6 +22723,28 @@
     method public static int getSize(android.view.View);
   }
 
+  public final class BidiFormatter {
+    method public static android.text.BidiFormatter getInstance();
+    method public static android.text.BidiFormatter getInstance(boolean);
+    method public static android.text.BidiFormatter getInstance(java.util.Locale);
+    method public boolean getStereoReset();
+    method public boolean isRtl(java.lang.String);
+    method public boolean isRtlContext();
+    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic);
+    method public java.lang.String unicodeWrap(java.lang.String, boolean);
+    method public java.lang.String unicodeWrap(java.lang.String);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale);
+    method public android.text.BidiFormatter build();
+    method public android.text.BidiFormatter.Builder setTextDirectionHeuristic(android.text.TextDirectionHeuristic);
+    method public android.text.BidiFormatter.Builder stereoReset(boolean);
+  }
+
   public class BoringLayout extends android.text.Layout implements android.text.TextUtils.EllipsizeCallback {
     ctor public BoringLayout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean);
     ctor public BoringLayout(java.lang.CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float, android.text.BoringLayout.Metrics, boolean, android.text.TextUtils.TruncateAt, int);
@@ -23120,49 +23239,6 @@
 
 }
 
-package android.text.bidi {
-
-  public final class BidiFormatter {
-    method public java.lang.String dirAttr(java.lang.String);
-    method public java.lang.String dirAttr(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.String dirAttr(boolean);
-    method public java.lang.String dirAttrValue(java.lang.String);
-    method public java.lang.String dirAttrValue(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.String dirAttrValue(boolean);
-    method public java.lang.String endEdge();
-    method public static android.text.bidi.BidiFormatter getInstance();
-    method public static android.text.bidi.BidiFormatter getInstance(boolean);
-    method public static android.text.bidi.BidiFormatter getInstance(java.util.Locale);
-    method public boolean getStereoReset();
-    method public boolean isRtl(java.lang.String);
-    method public boolean isRtlContext();
-    method public java.lang.String mark();
-    method public java.lang.String markAfter(java.lang.String);
-    method public java.lang.String markAfter(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.String markBefore(java.lang.String);
-    method public java.lang.String markBefore(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.String spanWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
-    method public java.lang.String spanWrap(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.String spanWrap(java.lang.String, boolean);
-    method public java.lang.String spanWrap(java.lang.String);
-    method public java.lang.String startEdge();
-    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic, boolean);
-    method public java.lang.String unicodeWrap(java.lang.String, android.text.TextDirectionHeuristic);
-    method public java.lang.String unicodeWrap(java.lang.String, boolean);
-    method public java.lang.String unicodeWrap(java.lang.String);
-  }
-
-  public static final class BidiFormatter.Builder {
-    ctor public BidiFormatter.Builder();
-    ctor public BidiFormatter.Builder(boolean);
-    ctor public BidiFormatter.Builder(java.util.Locale);
-    method public android.text.bidi.BidiFormatter build();
-    method public android.text.bidi.BidiFormatter.Builder setTextDirectionHeuristic(android.text.TextDirectionHeuristic);
-    method public android.text.bidi.BidiFormatter.Builder stereoReset(boolean);
-  }
-
-}
-
 package android.text.format {
 
   public class DateFormat {
@@ -24341,17 +24417,6 @@
     method public void set(T, V);
   }
 
-  public class PropertyValueModel extends android.util.ValueModel {
-    method public T get();
-    method public H getHost();
-    method public android.util.Property<H, T> getProperty();
-    method public java.lang.Class<T> getType();
-    method public static android.util.PropertyValueModel<H, T> of(H, android.util.Property<H, T>);
-    method public static android.util.PropertyValueModel<H, T> of(H, java.lang.Class<T>, java.lang.String);
-    method public static android.util.PropertyValueModel of(java.lang.Object, java.lang.String);
-    method public void set(T);
-  }
-
   public class SparseArray implements java.lang.Cloneable {
     ctor public SparseArray();
     ctor public SparseArray(int);
@@ -24518,14 +24583,6 @@
     field public int type;
   }
 
-  public abstract class ValueModel {
-    ctor protected ValueModel();
-    method public abstract T get();
-    method public abstract java.lang.Class<T> getType();
-    method public abstract void set(T);
-    field public static final android.util.ValueModel EMPTY;
-  }
-
   public class Xml {
     method public static android.util.AttributeSet asAttributeSet(org.xmlpull.v1.XmlPullParser);
     method public static android.util.Xml.Encoding findEncodingByName(java.lang.String) throws java.io.UnsupportedEncodingException;
@@ -28991,12 +29048,10 @@
     method public abstract void onSelectedDayChange(android.widget.CalendarView, int, int, int);
   }
 
-  public class CheckBox extends android.widget.CompoundButton implements android.widget.ValueEditor {
+  public class CheckBox extends android.widget.CompoundButton {
     ctor public CheckBox(android.content.Context);
     ctor public CheckBox(android.content.Context, android.util.AttributeSet);
     ctor public CheckBox(android.content.Context, android.util.AttributeSet, int);
-    method public android.util.ValueModel<java.lang.Boolean> getValueModel();
-    method public void setValueModel(android.util.ValueModel<java.lang.Boolean>);
   }
 
   public abstract interface Checkable {
@@ -29169,16 +29224,14 @@
     method public void setSize(int, int);
   }
 
-  public class EditText extends android.widget.TextView implements android.widget.ValueEditor {
+  public class EditText extends android.widget.TextView {
     ctor public EditText(android.content.Context);
     ctor public EditText(android.content.Context, android.util.AttributeSet);
     ctor public EditText(android.content.Context, android.util.AttributeSet, int);
     method public void extendSelection(int);
-    method public android.util.ValueModel<java.lang.CharSequence> getValueModel();
     method public void selectAll();
     method public void setSelection(int, int);
     method public void setSelection(int);
-    method public void setValueModel(android.util.ValueModel<java.lang.CharSequence>);
   }
 
   public abstract interface ExpandableListAdapter {
@@ -30049,7 +30102,6 @@
     method public void setRelativeScrollPosition(int, int);
     method public deprecated void setRemoteAdapter(int, int, android.content.Intent);
     method public void setRemoteAdapter(int, android.content.Intent);
-    method public void setRemoteAdapter(int, java.util.ArrayList<android.widget.RemoteViews>, int);
     method public void setScrollPosition(int, int);
     method public void setShort(int, java.lang.String, short);
     method public void setString(int, java.lang.String, java.lang.String);
@@ -30208,13 +30260,11 @@
     method public abstract java.lang.Object[] getSections();
   }
 
-  public class SeekBar extends android.widget.AbsSeekBar implements android.widget.ValueEditor {
+  public class SeekBar extends android.widget.AbsSeekBar {
     ctor public SeekBar(android.content.Context);
     ctor public SeekBar(android.content.Context, android.util.AttributeSet);
     ctor public SeekBar(android.content.Context, android.util.AttributeSet, int);
-    method public android.util.ValueModel<java.lang.Integer> getValueModel();
     method public void setOnSeekBarChangeListener(android.widget.SeekBar.OnSeekBarChangeListener);
-    method public void setValueModel(android.util.ValueModel<java.lang.Integer>);
   }
 
   public static abstract interface SeekBar.OnSeekBarChangeListener {
@@ -30802,11 +30852,6 @@
     method public android.widget.TextView getText2();
   }
 
-  public abstract interface ValueEditor {
-    method public abstract android.util.ValueModel<T> getValueModel();
-    method public abstract void setValueModel(android.util.ValueModel<T>);
-  }
-
   public class VideoView extends android.view.SurfaceView implements android.widget.MediaController.MediaPlayerControl {
     ctor public VideoView(android.content.Context);
     ctor public VideoView(android.content.Context, android.util.AttributeSet);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 0668be6..90bcb0fb 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -12,6 +12,7 @@
 #include <utils/Log.h>
 #include <cutils/process_name.h>
 #include <cutils/memory.h>
+#include <cutils/trace.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <sys/personality.h>
 
@@ -95,6 +96,9 @@
 
     virtual void onZygoteInit()
     {
+        // Re-enable tracing now that we're no longer in Zygote.
+        atrace_set_tracing_enabled(true);
+
         sp<ProcessState> proc = ProcessState::self();
         ALOGV("App process: starting thread pool.\n");
         proc->startThreadPool();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 31de98d..1e3d5be 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -308,6 +308,8 @@
      *     android:accessibilityFlags="flagDefault"
      *     android:settingsActivity="foo.bar.TestBackActivity"
      *     android:canRetrieveWindowContent="true"
+     *     android:canRequestTouchExplorationMode="true"
+     *     android:canRequestEnhancedWebAccessibility="true"
      *     . . .
      * /&gt;</pre>
      */
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index d82b9a3..40f45b7 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -29,6 +29,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.SparseArray;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.View;
@@ -38,7 +39,12 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import com.android.internal.R;
+
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * This class describes an {@link AccessibilityService}. The system notifies an
@@ -61,6 +67,49 @@
     private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";
 
     /**
+     * Capability: This accessibility service can retrieve the active window content.
+     */
+    public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
+
+    /**
+     * Capability: This accessibility service can request touch exploration mode in which
+     * touched items are spoken aloud and the UI can be explored via gestures.
+     */
+    public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
+
+    /**
+     * Capability: This accessibility service can request enhanced web accessibility
+     * enhancements. For example, installing scripts to make app content more accessible.
+     */
+    public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
+
+    /**
+      * Capability: This accessibility service can request to filter the key event stream.
+     */
+    public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
+
+    private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
+            new SparseArray<CapabilityInfo>();
+    static {
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+                new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
+                        R.string.capability_title_canRetrieveWindowContent,
+                        R.string.capability_desc_canRetrieveWindowContent));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+                new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
+                        R.string.capability_title_canRequestTouchExploration,
+                        R.string.capability_desc_canRequestTouchExploration));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
+                        R.string.capability_title_canRequestEnhancedWebAccessibility,
+                        R.string.capability_desc_canRequestEnhancedWebAccessibility));
+        sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+                new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
+                        R.string.capability_title_canRequestFilterKeyEvents,
+                        R.string.capability_desc_canRequestFilterKeyEvents));
+    }
+
+    /**
      * Denotes spoken feedback.
      */
     public static final int FEEDBACK_SPOKEN = 0x0000001;
@@ -152,9 +201,11 @@
      * <p>
      * For accessibility services targeting API version higher than
      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
-     * this flag have to request the
-     * {@link android.Manifest.permission#CAN_REQUEST_TOUCH_EXPLORATION_MODE}
-     * permission or the flag will be ignored.
+     * this flag have to declare this capability in their meta-data by setting
+     * the attribute {@link android.R.attr#canRequestTouchExplorationMode
+     * canRequestTouchExplorationMode} to true, otherwise this flag will
+     * be ignored. For how to declare the meta-data of a service refer to
+     * {@value AccessibilityService#SERVICE_META_DATA}.
      * </p>
      * <p>
      * Services targeting API version equal to or lower than
@@ -175,9 +226,11 @@
      * device will not have enhanced web accessibility enabled since there may be
      * another enabled service that requested it.
      * <p>
-     * Clients that want to set this flag have to request the
-     * {@link android.Manifest.permission#CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY}
-     * permission or the flag will be ignored.
+     * Services that want to set this flag have to declare this capability
+     * in their meta-data by setting the attribute {@link android.R.attr
+     * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
+     * true, otherwise this flag will be ignored. For how to declare the meta-data
+     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
      * </p>
      */
     public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
@@ -192,6 +245,25 @@
     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
 
     /**
+     * This flag requests from the system to filter key events. If this flag
+     * is set the accessibility service will receive the key events before
+     * applications allowing it implement global shortcuts. Setting this flag
+     * does not guarantee that this service will filter key events since only
+     * one service can do so at any given time. This avoids user confusion due
+     * to behavior change in case different key filtering services are enabled.
+     * If there is already another key filtering service enabled, this one will
+     * not receive key events.
+     * <p>
+     * Services that want to set this flag have to declare this capability
+     * in their meta-data by setting the attribute {@link android.R.attr
+     * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
+     * otherwise this flag will be ignored. For how to declare the meta-data
+     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
+     * </p>
+     */
+    public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
+
+    /**
      * The event types an {@link AccessibilityService} is interested in.
      * <p>
      *   <strong>Can be dynamically set at runtime.</strong>
@@ -259,6 +331,9 @@
      * @see #DEFAULT
      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+     * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+     * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
+     * @see #FLAG_REPORT_VIEW_IDS
      */
     public int flags;
 
@@ -279,9 +354,9 @@
     private String mSettingsActivityName;
 
     /**
-     * Flag whether this accessibility service can retrieve window content.
+     * Bit mask with capabilities of this service.
      */
-    private boolean mCanRetrieveWindowContent;
+    private int mCapabilities;
 
     /**
      * Resource id of the description of the accessibility service.
@@ -360,9 +435,22 @@
                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
             mSettingsActivityName = asAttributes.getString(
                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
-            mCanRetrieveWindowContent = asAttributes.getBoolean(
-                    com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
-                    false);
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRetrieveWindowContent, false)) {
+                mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
+            }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRequestTouchExplorationMode, false)) {
+                mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
+            }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
+                mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
+            }
+            if (asAttributes.getBoolean(com.android.internal.R.styleable
+                    .AccessibilityService_canRequestFilterKeyEvents, false)) {
+                mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
+            }
             TypedValue peekedValue = asAttributes.peekValue(
                     com.android.internal.R.styleable.AccessibilityService_description);
             if (peekedValue != null) {
@@ -446,9 +534,26 @@
      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
      * </p>
      * @return True if window content can be retrieved.
+     *
+     * @deprecated Use {@link #getCapabilities()}.
      */
     public boolean getCanRetrieveWindowContent() {
-        return mCanRetrieveWindowContent;
+        return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
+    }
+
+    /**
+     * Returns the bit mask of capabilities this accessibility service has such as
+     * being able to retrieve the active window content, etc.
+     *
+     * @return The capability bit mask.
+     *
+     * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
+     * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
+     * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+     * @see #CAPABILITY_FILTER_KEY_EVENTS
+     */
+    public int getCapabilities() {
+        return mCapabilities;
     }
 
     /**
@@ -502,7 +607,7 @@
         parcel.writeString(mId);
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
-        parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+        parcel.writeInt(mCapabilities);
         parcel.writeInt(mDescriptionResId);
         parcel.writeString(mNonLocalizedDescription);
     }
@@ -516,7 +621,7 @@
         mId = parcel.readString();
         mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
-        mCanRetrieveWindowContent = (parcel.readInt() == 1);
+        mCapabilities = parcel.readInt();
         mDescriptionResId = parcel.readInt();
         mNonLocalizedDescription = parcel.readString();
     }
@@ -567,7 +672,7 @@
         stringBuilder.append(", ");
         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
         stringBuilder.append(", ");
-        stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent);
+        appendCapabilities(stringBuilder, mCapabilities);
         return stringBuilder.toString();
     }
 
@@ -628,6 +733,20 @@
         stringBuilder.append("]");
     }
 
+    private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
+        stringBuilder.append("capabilities:");
+        stringBuilder.append("[");
+        while (capabilities != 0) {
+            final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
+            stringBuilder.append(capabilityToString(capabilityBit));
+            capabilities &= ~capabilityBit;
+            if (capabilities != 0) {
+                stringBuilder.append(", ");
+            }
+        }
+        stringBuilder.append("]");
+    }
+
     /**
      * Returns the string representation of a feedback type. For example,
      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
@@ -699,12 +818,77 @@
                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
+            case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
+                return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+            case FLAG_REPORT_VIEW_IDS:
+                return "FLAG_REPORT_VIEW_IDS";
+            case FLAG_REQUEST_FILTER_KEY_EVENTS:
+                return "FLAG_REQUEST_FILTER_KEY_EVENTS";
             default:
                 return null;
         }
     }
 
     /**
+     * Returns the string representation of a capability. For example,
+     * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
+     * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
+     *
+     * @param capability The capability.
+     * @return The string representation.
+     */
+    public static String capabilityToString(int capability) {
+        switch (capability) {
+            case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
+                return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
+            case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
+                return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
+            case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
+                return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
+            case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
+                return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
+    /**
+     * @hide
+     * @return The list of {@link CapabilityInfo} objects.
+     */
+    public List<CapabilityInfo> getCapabilityInfos() {
+        if (mCapabilities == 0) {
+            return Collections.emptyList();
+        }
+        int capabilities = mCapabilities;
+        List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
+        while (capabilities != 0) {
+            final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
+            capabilities &= ~capabilityBit;
+            CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
+            if (capabilityInfo != null) {
+                capabilityInfos.add(capabilityInfo);
+            }
+        }
+        return capabilityInfos;
+    }
+
+    /**
+     * @hide
+     */
+    public static final class CapabilityInfo {
+        public final int capability;
+        public final int titleResId;
+        public final int descResId;
+
+        public CapabilityInfo(int capability, int titleResId, int descResId) {
+            this.capability = capability;
+            this.titleResId = titleResId;
+            this.descResId = descResId;
+        }
+    }
+
+    /**
      * @see Parcelable.Creator
      */
     public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 241a64a..b4a12c4 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -405,6 +405,23 @@
     }
 
     /**
+     * Returns the accounts visible to the specified package, in an environment where some apps
+     * are not authorized to view all accounts. This method can only be called by system apps.
+     * @param type The type of accounts to return, null to retrieve all accounts
+     * @param packageName The package name of the app for which the accounts are to be returned
+     * @return An array of {@link Account}, one per matching account.  Empty
+     *     (never null) if no accounts of the specified type have been added.
+     */
+    public Account[] getAccountsByTypeForPackage(String type, String packageName) {
+        try {
+            return mService.getAccountsByTypeForPackage(type, packageName);
+        } 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
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 2aba163..58eb66f 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -34,13 +34,11 @@
 import android.widget.Button;
 import android.widget.ListView;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.internal.R;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -110,6 +108,7 @@
     private static final String KEY_INSTANCE_STATE_EXISTING_ACCOUNTS = "existingAccounts";
     private static final String KEY_INSTANCE_STATE_SELECTED_ACCOUNT_NAME = "selectedAccountName";
     private static final String KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT = "selectedAddAccount";
+    private static final String KEY_INSTANCE_STATE_ACCOUNT_LIST = "accountList";
 
     private static final int SELECTED_ITEM_NONE = -1;
 
@@ -169,6 +168,7 @@
 
             mSelectedAddNewAccount = savedInstanceState.getBoolean(
                     KEY_INSTANCE_STATE_SELECTED_ADD_ACCOUNT, false);
+            mAccounts = savedInstanceState.getParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST);
         } else {
             mPendingRequest = REQUEST_NULL;
             mExistingAccounts = null;
@@ -266,6 +266,7 @@
                         mAccounts.get(mSelectedItemIndex).name);
             }
         }
+        outState.putParcelableArrayList(KEY_INSTANCE_STATE_ACCOUNT_LIST, mAccounts);
     }
 
     public void onCancelButtonClicked(View view) {
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 8141813..86e279f 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -32,6 +32,7 @@
     AuthenticatorDescription[] getAuthenticatorTypes();
     Account[] getAccounts(String accountType);
     Account[] getAccountsForPackage(String packageName, int uid);
+    Account[] getAccountsByTypeForPackage(String type, String packageName);
     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);
diff --git a/core/java/android/animation/Animatable.java b/core/java/android/animation/Animatable.java
deleted file mode 100644
index f9ccb4d..0000000
--- a/core/java/android/animation/Animatable.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.animation;
-
-/**
- * This interface is implemented by animation-related classes that expose
- * the ability to set and get duration, startDelay, and interpolators.
- */
-public interface Animatable {
-
-    /**
-     * The amount of time, in milliseconds, to delay processing the animation
-     * after the animation is started. The {@link #setDuration(long)} of the
-     * animation will not begin to elapse until after the startDelay has elapsed.
-     *
-     * @return the number of milliseconds to delay running the animation
-     */
-    long getStartDelay();
-
-    /**
-     * The amount of time, in milliseconds, to delay processing the animation
-     * after the animation is started. The {@link #setDuration(long)} of the
-     * animation will not begin to elapse until after the startDelay has elapsed.
-
-     * @param startDelay The amount of the delay, in milliseconds
-     */
-    void setStartDelay(long startDelay);
-
-    /**
-     * Sets the length of the animation.
-     *
-     * @param duration The length of the animation, in milliseconds.
-     */
-    Animatable setDuration(long duration);
-
-    /**
-     * Gets the duration of the animation.
-     *
-     * @return The length of the animation, in milliseconds.
-     */
-    long getDuration();
-
-    /**
-     * The time interpolator used in calculating the elapsed fraction of the
-     * animation. The interpolator determines whether the animation runs with
-     * linear or non-linear motion, such as acceleration and deceleration.
-     *
-     * @param value the interpolator to be used by this animation
-     */
-    void setInterpolator(TimeInterpolator value);
-
-    /**
-     * Returns the timing interpolator that this animation uses.
-     *
-     * @return The timing interpolator for this animation.
-     */
-    public TimeInterpolator getInterpolator();
-}
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index da97d72..39eb8d6 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -22,21 +22,13 @@
  * This is the superclass for classes which provide basic support for animations which can be
  * started, ended, and have <code>AnimatorListeners</code> added to them.
  */
-public abstract class Animator implements Cloneable, Animatable {
+public abstract class Animator implements Cloneable {
 
     /**
      * The set of listeners to be sent events through the life of an animation.
      */
     ArrayList<AnimatorListener> mListeners = null;
 
-    @Override
-    public abstract Animator setDuration(long duration);
-
-    @Override
-    public TimeInterpolator getInterpolator() {
-        return null;
-    }
-
     /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
@@ -77,6 +69,55 @@
     }
 
     /**
+     * The amount of time, in milliseconds, to delay processing the animation
+     * after {@link #start()} is called.
+     *
+     * @return the number of milliseconds to delay running the animation
+     */
+    public abstract long getStartDelay();
+
+    /**
+     * The amount of time, in milliseconds, to delay processing the animation
+     * after {@link #start()} is called.
+
+     * @param startDelay The amount of the delay, in milliseconds
+     */
+    public abstract void setStartDelay(long startDelay);
+
+    /**
+     * Sets the duration of the animation.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     */
+    public abstract Animator setDuration(long duration);
+
+    /**
+     * Gets the duration of the animation.
+     *
+     * @return The length of the animation, in milliseconds.
+     */
+    public abstract long getDuration();
+
+    /**
+     * The time interpolator used in calculating the elapsed fraction of the
+     * animation. The interpolator determines whether the animation runs with
+     * linear or non-linear motion, such as acceleration and deceleration. The
+     * default value is {@link android.view.animation.AccelerateDecelerateInterpolator}.
+     *
+     * @param value the interpolator to be used by this animation
+     */
+    public abstract void setInterpolator(TimeInterpolator value);
+
+    /**
+     * Returns the timing interpolator that this animation uses.
+     *
+     * @return The timing interpolator for this animation.
+     */
+    public TimeInterpolator getInterpolator() {
+        return null;
+    }
+
+    /**
      * Returns whether this Animator is currently running (having been started and gone past any
      * initial startDelay period and not yet ended).
      *
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a26bdbc..6b5df7f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1353,8 +1353,8 @@
      * of the assist Intent.  The default implementation does nothing.
      *
      * <p>This function will be called after any global assist callbacks that had
-     * been registered with {@link Application#registerOnProvideAssistData
-     * Application.registerOnProvideAssistData}.
+     * been registered with {@link Application#registerOnProvideAssistDataListener
+     * Application.registerOnProvideAssistDataListener}.
      */
     public void onProvideAssistData(Bundle data) {
     }
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 7b07438..75e4bab 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -17,17 +17,14 @@
 package android.app;
 
 import java.util.ArrayList;
-import java.util.List;
 
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
-import android.content.RestrictionEntry;
 import android.content.res.Configuration;
 import android.os.Bundle;
-import android.os.UserManager;
 
 /**
  * Base class for those who need to maintain global application state. You can
@@ -49,7 +46,7 @@
             new ArrayList<ComponentCallbacks>();
     private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
             new ArrayList<ActivityLifecycleCallbacks>();
-    private ArrayList<OnProvideAssistData> mAssistCallbacks = null;
+    private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;
 
     /** @hide */
     public LoadedApk mLoadedApk;
@@ -65,10 +62,10 @@
     }
 
     /**
-     * Callback interface for use with {@link Application#registerOnProvideAssistData}
-     * and {@link Application#unregisterOnProvideAssistData}.
+     * Callback interface for use with {@link Application#registerOnProvideAssistDataListener}
+     * and {@link Application#unregisterOnProvideAssistDataListener}.
      */
-    public interface OnProvideAssistData {
+    public interface OnProvideAssistDataListener {
         /**
          * This is called when the user is requesting an assist, to build a full
          * {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
@@ -134,11 +131,6 @@
         }
     }
 
-    public List<RestrictionEntry> getApplicationRestrictions() {
-        return ((UserManager) getSystemService(USER_SERVICE))
-                .getApplicationRestrictions(getPackageName(), android.os.Process.myUserHandle());
-    }
-
     public void registerComponentCallbacks(ComponentCallbacks callback) {
         synchronized (mComponentCallbacks) {
             mComponentCallbacks.add(callback);
@@ -163,16 +155,16 @@
         }
     }
 
-    public void registerOnProvideAssistData(OnProvideAssistData callback) {
+    public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
         synchronized (this) {
             if (mAssistCallbacks == null) {
-                mAssistCallbacks = new ArrayList<OnProvideAssistData>();
+                mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>();
             }
             mAssistCallbacks.add(callback);
         }
     }
 
-    public void unregisterOnProvideAssistData(OnProvideAssistData callback) {
+    public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
         synchronized (this) {
             if (mAssistCallbacks != null) {
                 mAssistCallbacks.remove(callback);
@@ -285,7 +277,7 @@
         }
         if (callbacks != null) {
             for (int i=0; i<callbacks.length; i++) {
-                ((OnProvideAssistData)callbacks[i]).onProvideAssistData(activity, data);
+                ((OnProvideAssistDataListener)callbacks[i]).onProvideAssistData(activity, data);
             }
         }
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8284b2c..17e8dd9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1537,14 +1537,21 @@
         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.
+     * Used to determine if a particular package has been registered as a Device Owner app.
+     * A device owner app is a special device admin that cannot be deactivated by the user, once
+     * activated as a device admin. It also cannot be uninstalled. To check if a particular
+     * package is currently registered as the device owner app, pass in the package name from
+     * {@link Context#getPackageName()} to this method.<p/>This is useful for device
+     * admin apps that want to check if they are also registered as the device owner app. The
+     * exact mechanism by which a device admin app is registered as a device owner app is defined by
+     * the setup process.
+     * @param packageName the package name of the app, to compare with the registered device owner
+     * app, if any.
+     * @return whether or not the package is registered as the device owner app.
      */
-    public boolean isDeviceOwner(String packageName) {
+    public boolean isDeviceOwnerApp(String packageName) {
         if (mService != null) {
             try {
                 return mService.isDeviceOwner(packageName);
@@ -1555,6 +1562,14 @@
         return false;
     }
 
+    /**
+     * @hide
+     * Redirect to isDeviceOwnerApp.
+     */
+    public boolean isDeviceOwner(String packageName) {
+        return isDeviceOwnerApp(packageName);
+    }
+
     /** @hide */
     public String getDeviceOwner() {
         if (mService != null) {
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 37fddcb..67c772b 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -17,12 +17,15 @@
 package android.app.backup;
 
 import android.app.IBackupAgent;
+import android.app.QueuedWork;
 import android.app.backup.IBackupManager;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.ApplicationInfo;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
@@ -33,6 +36,7 @@
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.LinkedList;
+import java.util.concurrent.CountDownLatch;
 
 import libcore.io.ErrnoException;
 import libcore.io.Libcore;
@@ -122,6 +126,32 @@
     /** @hide */
     public static final int TYPE_SYMLINK = 3;
 
+    Handler mHandler = null;
+
+    class SharedPrefsSynchronizer implements Runnable {
+        public final CountDownLatch mLatch = new CountDownLatch(1);
+
+        @Override
+        public void run() {
+            QueuedWork.waitToFinish();
+            mLatch.countDown();
+        }
+    };
+
+    // Syncing shared preferences deferred writes needs to happen on the main looper thread
+    private void waitForSharedPrefs() {
+        if (mHandler == null) {
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+
+        final SharedPrefsSynchronizer s = new SharedPrefsSynchronizer();
+        mHandler.postAtFrontOfQueue(s);
+        try {
+            s.mLatch.await();
+        } catch (InterruptedException e) { /* ignored */ }
+    }
+
+
     public BackupAgent() {
         super(null);
     }
@@ -542,6 +572,11 @@
                 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
                 throw ex;
             } finally {
+                // Ensure that any SharedPreferences writes have landed after the backup,
+                // in case the app code has side effects (since apps cannot provide this
+                // guarantee themselves).
+                waitForSharedPrefs();
+
                 Binder.restoreCallingIdentity(ident);
                 try {
                     callbackBinder.opComplete(token);
@@ -569,6 +604,9 @@
                 Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
                 throw ex;
             } finally {
+                // Ensure that any side-effect SharedPreferences writes have landed
+                waitForSharedPrefs();
+
                 Binder.restoreCallingIdentity(ident);
                 try {
                     callbackBinder.opComplete(token);
@@ -586,6 +624,10 @@
 
             if (DEBUG) Log.v(TAG, "doFullBackup() invoked");
 
+            // Ensure that any SharedPreferences writes have landed *before*
+            // we potentially try to back up the underlying files directly.
+            waitForSharedPrefs();
+
             try {
                 BackupAgent.this.onFullBackup(new FullBackupDataOutput(data));
             } catch (IOException ex) {
@@ -595,6 +637,9 @@
                 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
                 throw ex;
             } finally {
+                // ... and then again after, as in the doBackup() case
+                waitForSharedPrefs();
+
                 // Send the EOD marker indicating that there is no more data
                 // forthcoming from this agent.
                 try {
@@ -624,6 +669,9 @@
             } catch (IOException e) {
                 throw new RuntimeException(e);
             } finally {
+                // Ensure that any side-effect SharedPreferences writes have landed
+                waitForSharedPrefs();
+
                 Binder.restoreCallingIdentity(ident);
                 try {
                     callbackBinder.opComplete(token);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2e9c9e3..3498bb8 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,7 +20,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.ParcelUuid;
@@ -30,11 +29,14 @@
 import android.util.Pair;
 
 import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.UUID;
@@ -357,9 +359,7 @@
     private final IBluetoothManager mManagerService;
     private IBluetooth mService;
 
-    private Handler mServiceRecordHandler;
-    private BluetoothAdapterCallback mCallback;
-    private int mClientIf;
+    private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients;
 
     /**
      * Get a handle to the default local Bluetooth adapter.
@@ -394,7 +394,7 @@
             mService = managerService.registerAdapter(mManagerCallback);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         mManagerService = managerService;
-        mServiceRecordHandler = null;
+        mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>();
     }
 
     /**
@@ -1409,72 +1409,38 @@
     }
 
     /**
-     * Register an callback to receive async results, such as LE scan result.
+     * Callback interface used to deliver LE scan results.
      *
-     * <p>This is an asynchronous call. The callback
-     * {@link BluetoothAdapterCallback#onCallbackRegistration}
-     * is used to notify success or failure if the function returns true.
-     *
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
-     *
-     * @param callback BluetootAdapter callback handler that will receive asynchronous callbacks.
-     * @return If true, the callback will be called to notify success or failure,
-     *         false on immediate error
+     * @see #startLeScan(LeScanCallback)
+     * @see #startLeScan(UUID[], LeScanCallback)
      */
-    public boolean registerCallback(BluetoothAdapterCallback callback) {
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            mCallback = callback;
-            UUID uuid = UUID.randomUUID();
-            if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
-
-            iGatt.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-    }
-
-    /**
-     * Unregister the registered callback.
-     */
-    public boolean unRegisterCallback(BluetoothAdapterCallback callback) {
-        if (callback != mCallback) return false;
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-
-            iGatt.unregisterClient(mClientIf);
-            return true;
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
+    public interface LeScanCallback {
+        /**
+         * Callback reporting an LE device found during a device scan initiated
+         * by the {@link BluetoothAdapter#startLeScan} function.
+         *
+         * @param device Identifies the remote device
+         * @param rssi The RSSI value for the remote device as reported by the
+         *             Bluetooth hardware. 0 if no RSSI value is available.
+         * @param scanRecord The content of the advertisement record offered by
+         *                   the remote device.
+         */
+        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
     }
 
     /**
      * Starts a scan for Bluetooth LE devices.
      *
      * <p>Results of the scan are reported using the
-     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     * {@link LeScanCallback#onLeScan} callback.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
+     * @param callback the callback LE scan results are delivered
      * @return true, if the scan was started successfully
      */
-    public boolean startLeScan() {
-        if (DBG) Log.d(TAG, "startLeScan()");
-        if (mClientIf == 0) return false;
-
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            iGatt.startScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
-            return false;
-        }
-
-        return true;
+    public boolean startLeScan(LeScanCallback callback) {
+        return startLeScan(null, callback);
     }
 
     /**
@@ -1482,155 +1448,281 @@
      * advertise given services.
      *
      * <p>Devices which advertise all specified services are reported using the
-     * {@link BluetoothAdapterCallback#onLeScan} callback.
+     * {@link LeScanCallback#onLeScan} callback.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
      *
      * @param serviceUuids Array of services to look for
+     * @param callback the callback LE scan results are delivered
      * @return true, if the scan was started successfully
      */
-    public boolean startLeScan(UUID[] serviceUuids) {
-        if (DBG) Log.d(TAG, "startLeScan() - with UUIDs");
-        if (mClientIf == 0) return false;
+    public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) {
+        if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
 
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            ParcelUuid[] uuids = new ParcelUuid[serviceUuids.length];
-            for(int i = 0; i != uuids.length; ++i) {
-                uuids[i] = new ParcelUuid(serviceUuids[i]);
-            }
-            iGatt.startScanWithUuids(mClientIf, false, uuids);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
+        if (callback == null) {
+            if (DBG) Log.e(TAG, "startLeScan: null callback");
             return false;
         }
 
-        return true;
+        synchronized(mLeScanClients) {
+            if (mLeScanClients.containsKey(callback)) {
+                if (DBG) Log.e(TAG, "LE Scan has already started");
+                return false;
+            }
+
+            try {
+                IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
+                UUID uuid = UUID.randomUUID();
+                GattCallbackWrapper wrapper = new GattCallbackWrapper(this, callback, serviceUuids);
+
+                iGatt.registerClient(new ParcelUuid(uuid), wrapper);
+                if (wrapper.scanStarted()) {
+                    mLeScanClients.put(callback, wrapper);
+                    return true;
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG,"",e);
+            }
+        }
+        return false;
     }
 
     /**
      * Stops an ongoing Bluetooth LE device scan.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback used to identify which scan to stop
+     *        must be the same handle used to start the scan
      */
-    public void stopLeScan() {
-        if (DBG) Log.d(TAG, "stopScan()");
-        if (mClientIf == 0) return;
-
-        try {
-            IBluetoothGatt iGatt = (IBluetoothGatt) mManagerService.getBluetoothGatt();
-            iGatt.stopScan(mClientIf, false);
-        } catch (RemoteException e) {
-            Log.e(TAG,"",e);
+    public void stopLeScan(LeScanCallback callback) {
+        if (DBG) Log.d(TAG, "stopLeScan()");
+        GattCallbackWrapper wrapper;
+        synchronized(mLeScanClients) {
+            wrapper = mLeScanClients.remove(callback);
+            if (wrapper == null) return;
         }
+        wrapper.stopLeScan();
     }
 
     /**
      * Bluetooth GATT interface callbacks
      */
-    private final IBluetoothGattCallback mBluetoothGattCallback =
-        new IBluetoothGattCallback.Stub() {
-            /**
-             * Application interface registered - app is ready to go
-             */
-            public void onClientRegistered(int status, int clientIf) {
-                if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status
-                    + " clientIf=" + clientIf);
-                mClientIf = clientIf;
-                mCallback.onCallbackRegistration(status == BluetoothGatt.GATT_SUCCESS ?
-                                  BluetoothAdapterCallback.CALLBACK_REGISTERED :
-                                  BluetoothAdapterCallback.CALLBACK_REGISTRATION_FAILURE);
-            }
+    private static class GattCallbackWrapper extends IBluetoothGattCallback.Stub {
+        private static final int LE_CALLBACK_REG_TIMEOUT = 2000;
+        private static final int LE_CALLBACK_REG_WAIT_COUNT = 5;
 
-            public void onClientConnectionState(int status, int clientIf,
-                                                boolean connected, String address) {
-                // no op
-            }
+        private final LeScanCallback mLeScanCb;
+        // mLeHandle 0: not registered
+        //           -1: scan stopped
+        //           >0: registered and scan started
+        private int mLeHandle;
+        private final UUID[] mScanFilter;
+        private WeakReference<BluetoothAdapter> mBluetoothAdapter;
 
-            /**
-             * Callback reporting an LE scan result.
-             * @hide
-             */
-            public void onScanResult(String address, int rssi, byte[] advData) {
-                if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+        public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter,
+                                   LeScanCallback leScanCb, UUID[] uuid) {
+            mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter);
+            mLeScanCb = leScanCb;
+            mScanFilter = uuid;
+            mLeHandle = 0;
+        }
 
-                try {
-                    mCallback.onLeScan(getRemoteDevice(address), rssi, advData);
-                } catch (Exception ex) {
-                    Log.w(TAG, "Unhandled exception: " + ex);
+        public boolean scanStarted() {
+            boolean started = false;
+            synchronized(this) {
+                if (mLeHandle == -1) return false;
+
+                int count = 0;
+                // wait for callback registration and LE scan to start
+                while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) {
+                    try {
+                        wait(LE_CALLBACK_REG_TIMEOUT);
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "Callback reg wait interrupted: " + e);
+                    }
+                    count++;
                 }
+                started = (mLeHandle > 0);
             }
+            return started;
+        }
 
-            public void onGetService(String address, int srvcType,
-                                     int srvcInstId, ParcelUuid srvcUuid) {
-                // no op
+        public void stopLeScan() {
+            synchronized(this) {
+                if (mLeHandle <= 0) {
+                    Log.e(TAG, "Error state, mLeHandle: " + mLeHandle);
+                    return;
+                }
+                BluetoothAdapter adapter = mBluetoothAdapter.get();
+                if (adapter != null) {
+                    try {
+                        IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt();
+                        iGatt.stopScan(mLeHandle, false);
+                        iGatt.unregisterClient(mLeHandle);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed to stop scan and unregister" + e);
+                    }
+                } else {
+                    Log.e(TAG, "stopLeScan, BluetoothAdapter is null");
+                }
+                mLeHandle = -1;
+                notifyAll();
             }
+        }
 
-            public void onGetIncludedService(String address, int srvcType,
-                                             int srvcInstId, ParcelUuid srvcUuid,
-                                             int inclSrvcType, int inclSrvcInstId,
-                                             ParcelUuid inclSrvcUuid) {
-                // no op
+        /**
+         * Application interface registered - app is ready to go
+         */
+        public void onClientRegistered(int status, int clientIf) {
+            if (DBG) Log.d(TAG, "onClientRegistered() - status=" + status +
+                           " clientIf=" + clientIf);
+            synchronized(this) {
+                if (mLeHandle == -1) {
+                    if (DBG) Log.d(TAG, "onClientRegistered LE scan canceled");
+                }
+
+                if (status == BluetoothGatt.GATT_SUCCESS) {
+                    mLeHandle = clientIf;
+                    IBluetoothGatt iGatt = null;
+                    try {
+                        BluetoothAdapter adapter = mBluetoothAdapter.get();
+                        if (adapter != null) {
+                            iGatt = adapter.getBluetoothManager().getBluetoothGatt();
+                            if (mScanFilter == null) {
+                                iGatt.startScan(mLeHandle, false);
+                            } else {
+                                ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length];
+                                for(int i = 0; i != uuids.length; ++i) {
+                                    uuids[i] = new ParcelUuid(mScanFilter[i]);
+                                }
+                                iGatt.startScanWithUuids(mLeHandle, false, uuids);
+                            }
+                        } else {
+                            Log.e(TAG, "onClientRegistered, BluetoothAdapter null");
+                            mLeHandle = -1;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "fail to start le scan: " + e);
+                        mLeHandle = -1;
+                    }
+                    if (mLeHandle == -1) {
+                        // registration succeeded but start scan failed
+                        if (iGatt != null) {
+                            try {
+                                iGatt.unregisterClient(mLeHandle);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "fail to unregister callback: " + mLeHandle +
+                                      " error: " + e);
+                            }
+                        }
+                    }
+                } else {
+                    // registration failed
+                    mLeHandle = -1;
+                }
+                notifyAll();
             }
+        }
 
-            public void onGetCharacteristic(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             int charProps) {
-                // no op
+        public void onClientConnectionState(int status, int clientIf,
+                                            boolean connected, String address) {
+            // no op
+        }
+
+        /**
+         * Callback reporting an LE scan result.
+         * @hide
+         */
+        public void onScanResult(String address, int rssi, byte[] advData) {
+            if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi);
+
+            // Check null in case the scan has been stopped
+            synchronized(this) {
+                if (mLeHandle <= 0) return;
             }
-
-            public void onGetDescriptor(String address, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descUuid) {
-                // no op
+            try {
+                BluetoothAdapter adapter = mBluetoothAdapter.get();
+                if (adapter == null) {
+                    Log.d(TAG, "onScanResult, BluetoothAdapter null");
+                    return;
+                }
+                mLeScanCb.onLeScan(adapter.getRemoteDevice(address), rssi, advData);
+            } catch (Exception ex) {
+                Log.w(TAG, "Unhandled exception: " + ex);
             }
+        }
 
-            public void onSearchComplete(String address, int status) {
-                // no op
-            }
+        public void onGetService(String address, int srvcType,
+                                 int srvcInstId, ParcelUuid srvcUuid) {
+            // no op
+        }
 
-            public void onCharacteristicRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid, byte[] value) {
-                // no op
-            }
+        public void onGetIncludedService(String address, int srvcType,
+                                         int srvcInstId, ParcelUuid srvcUuid,
+                                         int inclSrvcType, int inclSrvcInstId,
+                                         ParcelUuid inclSrvcUuid) {
+            // no op
+        }
 
-            public void onCharacteristicWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid) {
-                // no op
-            }
+        public void onGetCharacteristic(String address, int srvcType,
+                                        int srvcInstId, ParcelUuid srvcUuid,
+                                        int charInstId, ParcelUuid charUuid,
+                                        int charProps) {
+            // no op
+        }
 
-            public void onNotify(String address, int srvcType,
+        public void onGetDescriptor(String address, int srvcType,
+                                    int srvcInstId, ParcelUuid srvcUuid,
+                                    int charInstId, ParcelUuid charUuid,
+                                    ParcelUuid descUuid) {
+            // no op
+        }
+
+        public void onSearchComplete(String address, int status) {
+            // no op
+        }
+
+        public void onCharacteristicRead(String address, int status, int srvcType,
+                                         int srvcInstId, ParcelUuid srvcUuid,
+                                         int charInstId, ParcelUuid charUuid, byte[] value) {
+            // no op
+        }
+
+        public void onCharacteristicWrite(String address, int status, int srvcType,
+                                          int srvcInstId, ParcelUuid srvcUuid,
+                                          int charInstId, ParcelUuid charUuid) {
+            // no op
+        }
+
+        public void onNotify(String address, int srvcType,
                              int srvcInstId, ParcelUuid srvcUuid,
                              int charInstId, ParcelUuid charUuid,
                              byte[] value) {
-                // no op
-            }
+            // no op
+        }
 
-            public void onDescriptorRead(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descrUuid, byte[] value) {
-                // no op
-            }
+        public void onDescriptorRead(String address, int status, int srvcType,
+                                     int srvcInstId, ParcelUuid srvcUuid,
+                                     int charInstId, ParcelUuid charUuid,
+                                     ParcelUuid descrUuid, byte[] value) {
+            // no op
+        }
 
-            public void onDescriptorWrite(String address, int status, int srvcType,
-                             int srvcInstId, ParcelUuid srvcUuid,
-                             int charInstId, ParcelUuid charUuid,
-                             ParcelUuid descrUuid) {
-                // no op
-            }
+        public void onDescriptorWrite(String address, int status, int srvcType,
+                                      int srvcInstId, ParcelUuid srvcUuid,
+                                      int charInstId, ParcelUuid charUuid,
+                                      ParcelUuid descrUuid) {
+            // no op
+        }
 
-            public void onExecuteWrite(String address, int status) {
-                // no op
-            }
+        public void onExecuteWrite(String address, int status) {
+            // no op
+        }
 
-            public void onReadRemoteRssi(String address, int rssi, int status) {
-                // no op
-            }
-        };
+        public void onReadRemoteRssi(String address, int rssi, int status) {
+            // no op
+        }
+    }
 
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapterCallback.java b/core/java/android/bluetooth/BluetoothAdapterCallback.java
deleted file mode 100644
index a726bc9..0000000
--- a/core/java/android/bluetooth/BluetoothAdapterCallback.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.bluetooth.BluetoothDevice;
-
-/**
- * This abstract class is used to implement {@link BluetoothAdapter} callbacks.
- */
-public abstract class BluetoothAdapterCallback {
-
-    /**
-     * Indicates the callback has been registered successfully
-     */
-    public static final int CALLBACK_REGISTERED = 0;
-
-    /**
-     * Indicates the callback registration has failed
-     */
-    public static final int CALLBACK_REGISTRATION_FAILURE = 1;
-
-    /**
-     * Callback to inform change in registration state of the  application.
-     *
-     * @param status Returns {@link #CALLBACK_REGISTERED} if the application
-     *               was successfully registered.
-     */
-    public void onCallbackRegistration(int status) {
-    }
-
-    /**
-     * Callback reporting an LE device found during a device scan initiated
-     * by the {@link BluetoothAdapter#startLeScan} function.
-     *
-     * @param device Identifies the remote device
-     * @param rssi The RSSI value for the remote device as reported by the
-     *             Bluetooth hardware. 0 if no RSSI value is available.
-     * @param scanRecord The content of the advertisement record offered by
-     *                   the remote device.
-     */
-    public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
-    }
-}
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 19083b5..172f3bc 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -127,7 +127,7 @@
 
         try {
             IBluetoothManager managerService = mAdapter.getBluetoothManager();
-            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
             if (iGatt == null) return connectedDevices;
 
             connectedDevices = iGatt.getDevicesMatchingConnectionStates(
@@ -172,7 +172,7 @@
 
         try {
             IBluetoothManager managerService = mAdapter.getBluetoothManager();
-            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
             if (iGatt == null) return devices;
             devices = iGatt.getDevicesMatchingConnectionStates(states);
         } catch (RemoteException e) {
@@ -203,7 +203,7 @@
 
         try {
             IBluetoothManager managerService = mAdapter.getBluetoothManager();
-            IBluetoothGatt iGatt = (IBluetoothGatt) managerService.getBluetoothGatt();
+            IBluetoothGatt iGatt = managerService.getBluetoothGatt();
             if (iGatt == null) {
                 Log.e(TAG, "Fail to get GATT Server connection");
                 return null;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 03e241a..5bd28b9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -293,15 +293,6 @@
     public abstract Context getApplicationContext();
 
     /**
-     * Returns the list of restrictions for the application, or null if there are no
-     * restrictions.
-     * @return
-     */
-    public List<RestrictionEntry> getApplicationRestrictions() {
-        return getApplicationContext().getApplicationRestrictions();
-    }
-
-    /**
      * Add a new {@link ComponentCallbacks} to the base application of the
      * Context, which will be called at the same times as the ComponentCallbacks
      * methods of activities and other components are called.  Note that you
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 97ad7dd..67bd952 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2417,11 +2417,16 @@
 
     /**
      * Broadcast to a specific application to query any supported restrictions to impose
-     * on restricted users. The response should contain an extra {@link #EXTRA_RESTRICTIONS},
+     * on restricted users. The broadcast intent contains an extra
+     * {@link #EXTRA_RESTRICTIONS_BUNDLE} with the currently persisted
+     * restrictions as a Bundle of key/value pairs. The value types can be Boolean, String or
+     * String[] depending on the restriction type.<p/>
+     * The response should contain an extra {@link #EXTRA_RESTRICTIONS_LIST},
      * which is of type <code>ArrayList&lt;RestrictionEntry&gt;</code>. It can also
      * contain an extra {@link #EXTRA_RESTRICTIONS_INTENT}, which is of type <code>Intent</code>.
      * The activity specified by that intent will be launched for a result which must contain
-     * the extra {@link #EXTRA_RESTRICTIONS}. The returned restrictions will be persisted.
+     * one of the extras {@link #EXTRA_RESTRICTIONS_LIST} or {@link #EXTRA_RESTRICTIONS_BUNDLE}.
+     * The keys and values of the returned restrictions will be persisted.
      * @see RestrictionEntry
      */
     public static final String ACTION_GET_RESTRICTION_ENTRIES =
@@ -3160,7 +3165,8 @@
         "android.intent.extra.ALLOW_MULTIPLE";
 
     /**
-     * The userHandle carried with broadcast intents related to addition, removal and switching of users
+     * The userHandle carried with broadcast intents related to addition, removal and switching of
+     * users
      * - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}.
      * @hide
      */
@@ -3169,9 +3175,18 @@
 
     /**
      * Extra used in the response from a BroadcastReceiver that handles
-     * {@link #ACTION_GET_RESTRICTION_ENTRIES}.
+     * {@link #ACTION_GET_RESTRICTION_ENTRIES}. The type of the extra is
+     * <code>ArrayList&lt;RestrictionEntry&gt;</code>.
      */
-    public static final String EXTRA_RESTRICTIONS = "android.intent.extra.restrictions";
+    public static final String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
+
+    /**
+     * Extra sent in the intent to the BroadcastReceiver that handles
+     * {@link #ACTION_GET_RESTRICTION_ENTRIES}. The type of the extra is a Bundle containing
+     * the restrictions as key/value pairs.
+     */
+    public static final String EXTRA_RESTRICTIONS_BUNDLE =
+            "android.intent.extra.restrictions_bundle";
 
     /**
      * Extra used in the response from a BroadcastReceiver that handles
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 86d6ee7..905ae0d 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1219,12 +1219,12 @@
      * Return the layout direction. Will be either {@link View#LAYOUT_DIRECTION_LTR} or
      * {@link View#LAYOUT_DIRECTION_RTL}.
      *
-     * @return the layout direction
+     * @return Returns {@link View#LAYOUT_DIRECTION_RTL} if the configuration
+     * is {@link #SCREENLAYOUT_LAYOUTDIR_RTL}, otherwise {@link View#LAYOUT_DIRECTION_LTR}.
      */
     public int getLayoutDirection() {
-        // We need to substract one here as the configuration values are using "0" as undefined thus
-        // having LRT set to "1" and RTL set to "2"
-        return ((screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) >> SCREENLAYOUT_LAYOUTDIR_SHIFT) - 1;
+        return (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK) == SCREENLAYOUT_LAYOUTDIR_RTL
+                ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
     }
 
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d64bff9..42f4faf 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -17,6 +17,7 @@
 package android.content.res;
 
 import android.os.Trace;
+import android.view.View;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -80,16 +81,16 @@
 
     private static final Object sSync = new Object();
     /*package*/ static Resources mSystem = null;
-    
+
     // Information about preloaded resources.  Note that they are not
     // protected by a lock, because while preloading in zygote we are all
     // single-threaded, and after that these are immutable.
-    private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables
+    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
+    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
             = new LongSparseArray<Drawable.ConstantState>();
     private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
             = new LongSparseArray<ColorStateList>();
-    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
-            = new LongSparseArray<Drawable.ConstantState>();
+
     private static boolean sPreloaded;
     private static int sPreloadedDensity;
 
@@ -120,6 +121,12 @@
     
     private CompatibilityInfo mCompatibilityInfo;
 
+    static {
+        sPreloadedDrawables = new LongSparseArray[2];
+        sPreloadedDrawables[0] = new LongSparseArray<Drawable.ConstantState>();
+        sPreloadedDrawables[1] = new LongSparseArray<Drawable.ConstantState>();
+    }
+
     /** @hide */
     public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
         return selectSystemTheme(curTheme, targetSdkVersion,
@@ -1978,12 +1985,14 @@
         }
     }
 
-    static private final int VARYING_CONFIGS = ActivityInfo.activityInfoConfigToNative(
-            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
-
-    private boolean verifyPreloadConfig(int changingConfigurations, int resourceId, String name) {
+    private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
+            int resourceId, String name) {
+        // We allow preloading of resources even if they vary by font scale (which
+        // doesn't impact resource selection) or density (which we handle specially by
+        // simply turning off all preloading), as well as any other configs specified
+        // by the caller.
         if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
-                ActivityInfo.CONFIG_DENSITY)) & VARYING_CONFIGS) != 0) {
+                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
             String resName;
             try {
                 resName = getResourceName(resourceId);
@@ -1995,9 +2004,23 @@
                     + " (" + resName + ") that varies with configuration!!");
             return false;
         }
+        if (TRACE_FOR_PRELOAD) {
+            String resName;
+            try {
+                resName = getResourceName(resourceId);
+            } catch (NotFoundException e) {
+                resName = "?";
+            }
+            Log.w(TAG, "Preloading " + name + " resource #0x"
+                    + Integer.toHexString(resourceId)
+                    + " (" + resName + ")");
+        }
         return true;
     }
 
+    static private final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
+            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
+
     /*package*/ Drawable loadDrawable(TypedValue value, int id)
             throws NotFoundException {
 
@@ -2022,11 +2045,12 @@
         if (dr != null) {
             return dr;
         }
-
-        Drawable.ConstantState cs = isColorDrawable
-                ? sPreloadedColorDrawables.get(key)
-                : (sPreloadedDensity == mConfiguration.densityDpi
-                        ? sPreloadedDrawables.get(key) : null);
+        Drawable.ConstantState cs;
+        if (isColorDrawable) {
+            cs = sPreloadedColorDrawables.get(key);
+        } else {
+            cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
+        }
         if (cs != null) {
             dr = cs.newDrawable(this);
         } else {
@@ -2100,11 +2124,26 @@
             cs = dr.getConstantState();
             if (cs != null) {
                 if (mPreloading) {
-                    if (verifyPreloadConfig(cs.getChangingConfigurations(), value.resourceId, "drawable")) {
-                        if (isColorDrawable) {
+                    final int changingConfigs = cs.getChangingConfigurations();
+                    if (isColorDrawable) {
+                        if (verifyPreloadConfig(changingConfigs, 0, value.resourceId,
+                                "drawable")) {
                             sPreloadedColorDrawables.put(key, cs);
-                        } else {
-                            sPreloadedDrawables.put(key, cs);
+                        }
+                    } else {
+                        if (verifyPreloadConfig(changingConfigs,
+                                LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
+                            if ((changingConfigs&LAYOUT_DIR_CONFIG) == 0) {
+                                // If this resource does not vary based on layout direction,
+                                // we can put it in all of the preload maps.
+                                sPreloadedDrawables[0].put(key, cs);
+                                sPreloadedDrawables[1].put(key, cs);
+                            } else {
+                                // Otherwise, only in the layout dir we loaded it for.
+                                final LongSparseArray<Drawable.ConstantState> preloads
+                                        = sPreloadedDrawables[mConfiguration.getLayoutDirection()];
+                                preloads.put(key, cs);
+                            }
                         }
                     }
                 } else {
@@ -2170,7 +2209,8 @@
 
             csl = ColorStateList.valueOf(value.data);
             if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, value.resourceId, "color")) {
+                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                        "color")) {
                     sPreloadedColorStateLists.put(key, csl);
                 }
             }
@@ -2219,7 +2259,8 @@
 
         if (csl != null) {
             if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, value.resourceId, "color")) {
+                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                        "color")) {
                     sPreloadedColorStateLists.put(key, csl);
                 }
             } else {
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 35bbb9c..e67d0d7 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -129,6 +129,9 @@
 
     private HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>
             mCallbacks = new HashMap<GeofenceHardwareCallback, GeofenceHardwareCallbackWrapper>();
+    private HashMap<GeofenceHardwareMonitorCallback, GeofenceHardwareMonitorCallbackWrapper>
+            mMonitorCallbacks = new HashMap<GeofenceHardwareMonitorCallback,
+                    GeofenceHardwareMonitorCallbackWrapper>();
     /**
      * @hide
      */
@@ -137,8 +140,29 @@
     }
 
     /**
-     * Returns all the hardware geofence monitoring systems and their status.
-     * Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
+     * Returns all the hardware geofence monitoring systems which are supported
+     *
+     * <p> Call {@link #getStatusOfMonitoringType(int)} to know the current state
+     * of a monitoring system.
+     *
+     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
+     * geofencing in hardware.
+     *
+     * @return An array of all the monitoring types.
+     *         An array of length 0 is returned in case of errors.
+     */
+    public int[] getMonitoringTypes() {
+        try {
+            return mService.getMonitoringTypes();
+        } catch (RemoteException e) {
+        }
+        return new int[0];
+    }
+
+    /**
+     * Returns current status of a hardware geofence monitoring system.
+     *
+     * <p>Status can be one of {@link #MONITOR_CURRENTLY_AVAILABLE},
      * {@link #MONITOR_CURRENTLY_UNAVAILABLE} or {@link #MONITOR_UNSUPPORTED}
      *
      * <p> Some supported hardware monitoring systems might not be available
@@ -147,18 +171,15 @@
      * geofences and will change from {@link #MONITOR_CURRENTLY_AVAILABLE} to
      * {@link #MONITOR_CURRENTLY_UNAVAILABLE}.
      *
-     * <p> Requires {@link android.Manifest.permission#LOCATION_HARDWARE} permission to access
-     * geofencing in hardware.
-     *
-     * @return An array indexed by the various monitoring types and their status.
-     *         An array of length 0 is returned in case of errors.
+     * @param monitoringType
+     * @return Current status of the monitoring type.
      */
-    public int[] getMonitoringTypesAndStatus() {
+    public int getStatusOfMonitoringType(int monitoringType) {
         try {
-            return mService.getMonitoringTypesAndStatus();
+            return mService.getStatusOfMonitoringType(monitoringType);
         } catch (RemoteException e) {
+            return MONITOR_UNSUPPORTED;
         }
-        return new int[0];
     }
 
     /**
@@ -167,8 +188,10 @@
      * <p> When the device detects that is has entered, exited or is uncertain
      * about the area specified by the geofence, the given callback will be called.
      *
-     * <p> The {@link GeofenceHardwareCallback#onGeofenceChange} callback will be called,
-     * with the following parameters
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofenceAdd} will be called with the result of the
+     * add call from the hardware. The {@link GeofenceHardwareCallback#onGeofenceAdd} will be
+     * called with the following parameters when a transition event occurs.
      * <ul>
      * <li> The geofence Id
      * <li> The location object indicating the last known location.
@@ -195,43 +218,46 @@
      * which abstracts the hardware should be used instead. All the checks are done by the higher
      * level public API. Any needed locking should be handled by the higher level API.
      *
-     * @param latitude Latitude of the area to be monitored.
-     * @param longitude Longitude of the area to be monitored.
-     * @param radius Radius (in meters) of the area to be monitored.
-     * @param lastTransition The current state of the geofence. Can be one of
-     *        {@link #GEOFENCE_ENTERED}, {@link #GEOFENCE_EXITED},
-     *        {@link #GEOFENCE_UNCERTAIN}.
-     * @param monitorTransitions Bitwise OR of {@link #GEOFENCE_ENTERED},
-     *        {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
-     * @param notificationResponsivenes Defines the best-effort description
-     *        of how soon should the callback be called when the transition
-     *        associated with the Geofence is triggered. For instance, if
-     *        set to 1000 millseconds with {@link #GEOFENCE_ENTERED},
-     *        the callback will be called 1000 milliseconds within entering
-     *        the geofence. This parameter is defined in milliseconds.
-     * @param unknownTimer The time limit after which the
-     *        {@link #GEOFENCE_UNCERTAIN} transition
-     *        should be triggered. This paramter is defined in milliseconds.
+     * <p> Create a geofence request object using the methods in {@link GeofenceHardwareRequest} to
+     * set all the characteristics of the geofence. Use the created GeofenceHardwareRequest object
+     * in this call.
+     *
+     * @param geofenceId The id associated with the geofence.
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
+     * @param geofenceRequest The {@link GeofenceHardwareRequest} object associated with the
+     *        geofence.
      * @param callback {@link GeofenceHardwareCallback} that will be use to notify the
      *        transition.
-     * @return true on success.
+     * @return true when the geofence is successfully sent to the hardware for addition.
+     * @throws IllegalArgumentException when the geofence request type is not supported.
      */
-    public boolean addCircularFence(int geofenceId, double latitude, double longitude,
-            double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
-            int unknownTimer, int monitoringType, GeofenceHardwareCallback callback) {
+    public boolean addGeofence(int geofenceId, int monitoringType, GeofenceHardwareRequest
+            geofenceRequest, GeofenceHardwareCallback callback) {
         try {
-            return mService.addCircularFence(geofenceId, latitude, longitude, radius,
-                    lastTransition, monitorTransitions, notificationResponsivenes, unknownTimer,
-                    monitoringType, getCallbackWrapper(callback));
+            if (geofenceRequest.getType() == GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) {
+                return mService.addCircularFence(geofenceId, monitoringType,
+                        geofenceRequest.getLatitude(),
+                        geofenceRequest.getLongitude(), geofenceRequest.getRadius(),
+                        geofenceRequest.getLastTransition(),
+                        geofenceRequest.getMonitorTransitions(),
+                        geofenceRequest.getNotificationResponsiveness(),
+                        geofenceRequest.getUnknownTimer(),
+                        getCallbackWrapper(callback));
+            } else {
+                throw new IllegalArgumentException("Geofence Request type not supported");
+            }
         } catch (RemoteException e) {
         }
         return false;
     }
 
     /**
-     * Removes a geofence added by {@link #addCircularFence} call.
+     * Removes a geofence added by {@link #addGeofence} call.
+     *
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofenceRemove} will be called with the result of the
+     * remove call from the hardware.
      *
      * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
      * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -246,7 +272,7 @@
      * @param geofenceId The id of the geofence.
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
-     * @return true on success.
+     * @return true when the geofence is successfully sent to the hardware for removal.                     .
      */
    public boolean removeGeofence(int geofenceId, int monitoringType) {
        try {
@@ -257,7 +283,11 @@
    }
 
     /**
-     * Pauses the monitoring of a geofence added by {@link #addCircularFence} call.
+     * Pauses the monitoring of a geofence added by {@link #addGeofence} call.
+     *
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofencePause} will be called with the result of the
+     * pause call from the hardware.
      *
      * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
      * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
@@ -272,7 +302,7 @@
      * @param geofenceId The id of the geofence.
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
-     * @return true on success.
+     * @return true when the geofence is successfully sent to the hardware for pausing.
      */
     public boolean pauseGeofence(int geofenceId, int monitoringType) {
         try {
@@ -285,6 +315,10 @@
     /**
      * Resumes the monitoring of a geofence added by {@link #pauseGeofence} call.
      *
+     * <p> If this call returns true, it means that the geofence has been sent to the hardware.
+     * {@link GeofenceHardwareCallback#onGeofenceResume} will be called with the result of the
+     * resume call from the hardware.
+     *
      * <p> Requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission when
      * {@link #MONITORING_TYPE_GPS_HARDWARE} is used.
      *
@@ -296,15 +330,15 @@
      * level public API. Any needed locking should be handled by the higher level API.
      *
      * @param geofenceId The id of the geofence.
-     * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
-     *        {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
      * @param monitoringType The type of the hardware subsystem that should be used
      *        to monitor the geofence.
-     * @return true on success.
+     * @param monitorTransition Bitwise OR of {@link #GEOFENCE_ENTERED},
+     *        {@link #GEOFENCE_EXITED}, {@link #GEOFENCE_UNCERTAIN}
+     * @return true when the geofence is successfully sent to the hardware for resumption.
      */
-    public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+    public boolean resumeGeofence(int geofenceId, int monitoringType, int monitorTransition) {
         try {
-            return mService.resumeGeofence(geofenceId, monitorTransition, monitoringType);
+            return mService.resumeGeofence(geofenceId, monitoringType, monitorTransition);
         } catch (RemoteException e) {
         }
         return false;
@@ -333,10 +367,10 @@
      * @return true on success
      */
     public boolean registerForMonitorStateChangeCallback(int monitoringType,
-            GeofenceHardwareCallback callback) {
+            GeofenceHardwareMonitorCallback callback) {
         try {
             return mService.registerForMonitorStateChangeCallback(monitoringType,
-                    getCallbackWrapper(callback));
+                    getMonitorCallbackWrapper(callback));
         } catch (RemoteException e) {
         }
         return false;
@@ -361,12 +395,12 @@
      * @return true on success
      */
     public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-            GeofenceHardwareCallback callback) {
+            GeofenceHardwareMonitorCallback callback) {
         boolean  result = false;
         try {
             result = mService.unregisterForMonitorStateChangeCallback(monitoringType,
-                    getCallbackWrapper(callback));
-            if (result) removeCallback(callback);
+                    getMonitorCallbackWrapper(callback));
+            if (result) removeMonitorCallback(callback);
 
         } catch (RemoteException e) {
         }
@@ -391,6 +425,38 @@
         }
     }
 
+    private void removeMonitorCallback(GeofenceHardwareMonitorCallback callback) {
+        synchronized (mMonitorCallbacks) {
+            mMonitorCallbacks.remove(callback);
+        }
+    }
+
+    private GeofenceHardwareMonitorCallbackWrapper getMonitorCallbackWrapper(
+            GeofenceHardwareMonitorCallback callback) {
+        synchronized (mMonitorCallbacks) {
+            GeofenceHardwareMonitorCallbackWrapper wrapper = mMonitorCallbacks.get(callback);
+            if (wrapper == null) {
+                wrapper = new GeofenceHardwareMonitorCallbackWrapper(callback);
+                mMonitorCallbacks.put(callback, wrapper);
+            }
+            return wrapper;
+        }
+    }
+
+    class GeofenceHardwareMonitorCallbackWrapper extends IGeofenceHardwareMonitorCallback.Stub {
+        private WeakReference<GeofenceHardwareMonitorCallback> mCallback;
+
+        GeofenceHardwareMonitorCallbackWrapper(GeofenceHardwareMonitorCallback c) {
+            mCallback = new WeakReference<GeofenceHardwareMonitorCallback>(c);
+        }
+
+        public void onMonitoringSystemChange(int monitoringType, boolean available,
+                Location location) {
+            GeofenceHardwareMonitorCallback c = mCallback.get();
+            if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
+        }
+    }
+
     class GeofenceHardwareCallbackWrapper extends IGeofenceHardwareCallback.Stub {
         private WeakReference<GeofenceHardwareCallback> mCallback;
 
@@ -398,17 +464,11 @@
             mCallback = new WeakReference<GeofenceHardwareCallback>(c);
         }
 
-        public void onMonitoringSystemChange(int monitoringType, boolean available,
-                Location location) {
-            GeofenceHardwareCallback c = mCallback.get();
-            if (c != null) c.onMonitoringSystemChange(monitoringType, available, location);
-        }
-
-        public void onGeofenceChange(int geofenceId, int transition, Location location,
+        public void onGeofenceTransition(int geofenceId, int transition, Location location,
                 long timestamp, int monitoringType) {
             GeofenceHardwareCallback c = mCallback.get();
             if (c != null) {
-                c.onGeofenceChange(geofenceId, transition, location, timestamp,
+                c.onGeofenceTransition(geofenceId, transition, location, timestamp,
                         monitoringType);
             }
         }
@@ -428,7 +488,9 @@
 
         public void onGeofencePause(int geofenceId, int status) {
             GeofenceHardwareCallback c = mCallback.get();
-            if (c != null) c.onGeofencePause(geofenceId, status);
+            if (c != null) {
+                c.onGeofencePause(geofenceId, status);
+            }
         }
 
         public void onGeofenceResume(int geofenceId, int status) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareCallback.java b/core/java/android/hardware/location/GeofenceHardwareCallback.java
index 8ab582a..6cad3da 100644
--- a/core/java/android/hardware/location/GeofenceHardwareCallback.java
+++ b/core/java/android/hardware/location/GeofenceHardwareCallback.java
@@ -22,19 +22,6 @@
  * The callback class associated with the APIs in {@link GeofenceHardware}
  */
 public abstract class GeofenceHardwareCallback {
-
-    /**
-     * The callback called when the state of a monitoring system changes.
-     * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
-     * monitoring system.
-     *
-     * @param monitoringType The type of the monitoring system.
-     * @param available Indicates whether the system is currently available or not.
-     * @param location The last known location according to the monitoring system.
-     */
-    public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
-    }
-
     /**
      * The callback called when there is a transition to report for the specific
      * geofence.
@@ -47,7 +34,7 @@
      *        detected
      * @param monitoringType Type of the monitoring system.
      */
-    public void onGeofenceChange(int geofenceId, int transition, Location location,
+    public void onGeofenceTransition(int geofenceId, int transition, Location location,
             long timestamp, int monitoringType) {
     }
 
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 21f1ea6..a62b660 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -21,8 +21,10 @@
 import android.location.IGpsGeofenceHardware;
 import android.location.Location;
 import android.location.LocationManager;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -48,8 +50,9 @@
     private PowerManager.WakeLock mWakeLock;
     private SparseArray<IGeofenceHardwareCallback> mGeofences =
             new SparseArray<IGeofenceHardwareCallback>();
-    private ArrayList<IGeofenceHardwareCallback>[] mCallbacks =
+    private ArrayList<IGeofenceHardwareMonitorCallback>[] mCallbacks =
             new ArrayList[GeofenceHardware.NUM_MONITORS];
+    private ArrayList<Reaper> mReapers = new ArrayList<Reaper>();
 
     private IGpsGeofenceHardware mGpsService;
 
@@ -63,11 +66,18 @@
     private static final int RESUME_GEOFENCE_CALLBACK = 5;
     private static final int ADD_GEOFENCE = 6;
     private static final int REMOVE_GEOFENCE = 7;
+    private static final int GEOFENCE_CALLBACK_BINDER_DIED = 8;
 
     // mCallbacksHandler message types
     private static final int GPS_GEOFENCE_STATUS = 1;
     private static final int CALLBACK_ADD = 2;
     private static final int CALLBACK_REMOVE = 3;
+    private static final int MONITOR_CALLBACK_BINDER_DIED = 4;
+
+    // mReaperHandler message types
+    private static final int REAPER_GEOFENCE_ADDED = 1;
+    private static final int REAPER_MONITOR_CALLBACK_ADDED = 2;
+    private static final int REAPER_REMOVED = 3;
 
     // The following constants need to match GpsLocationFlags enum in gps.h
     private static final int LOCATION_INVALID = 0;
@@ -151,15 +161,28 @@
         }
     }
 
-    public int[] getMonitoringTypesAndStatus() {
+    public int[] getMonitoringTypes() {
         synchronized (mSupportedMonitorTypes) {
-            return mSupportedMonitorTypes;
+            if (mSupportedMonitorTypes[GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE] !=
+                        GeofenceHardware.MONITOR_UNSUPPORTED) {
+                return new int[] {GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE};
+            }
+            return new int[0];
         }
     }
 
-    public boolean addCircularFence(int geofenceId, double latitude, double longitude,
-            double radius, int lastTransition,int monitorTransitions, int notificationResponsivenes,
-            int unknownTimer, int monitoringType, IGeofenceHardwareCallback callback) {
+    public int getStatusOfMonitoringType(int monitoringType) {
+        synchronized (mSupportedMonitorTypes) {
+            if (monitoringType >= mSupportedMonitorTypes.length || monitoringType < 0) {
+                throw new IllegalArgumentException("Unknown monitoring type");
+            }
+            return mSupportedMonitorTypes[monitoringType];
+        }
+    }
+
+    public boolean addCircularFence(int geofenceId,  int monitoringType, double latitude,
+            double longitude, double radius, int lastTransition,int monitorTransitions,
+            int notificationResponsivenes, int unknownTimer, IGeofenceHardwareCallback callback) {
         // This API is not thread safe. Operations on the same geofence need to be serialized
         // by upper layers
         if (DEBUG) {
@@ -190,7 +213,11 @@
             default:
                 result = false;
         }
-        if (!result) {
+        if (result) {
+            m = mReaperHandler.obtainMessage(REAPER_GEOFENCE_ADDED, callback);
+            m.arg1 = monitoringType;
+            mReaperHandler.sendMessage(m);
+        } else {
             m = mGeofenceHandler.obtainMessage(REMOVE_GEOFENCE);
             m.arg1 = geofenceId;
             mGeofenceHandler.sendMessage(m);
@@ -245,7 +272,7 @@
     }
 
 
-    public boolean resumeGeofence(int geofenceId, int monitorTransition, int monitoringType) {
+    public boolean resumeGeofence(int geofenceId,  int monitoringType, int monitorTransition) {
         // This API is not thread safe. Operations on the same geofence need to be serialized
         // by upper layers
         if (DEBUG) Log.d(TAG, "Resume Geofence: GeofenceId: " + geofenceId);
@@ -268,7 +295,12 @@
     }
 
     public boolean registerForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback) {
+            IGeofenceHardwareMonitorCallback callback) {
+        Message reaperMessage =
+                mReaperHandler.obtainMessage(REAPER_MONITOR_CALLBACK_ADDED, callback);
+        reaperMessage.arg1 = monitoringType;
+        mReaperHandler.sendMessage(reaperMessage);
+
         Message m = mCallbacksHandler.obtainMessage(CALLBACK_ADD, callback);
         m.arg1 = monitoringType;
         mCallbacksHandler.sendMessage(m);
@@ -276,7 +308,7 @@
     }
 
     public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback) {
+            IGeofenceHardwareMonitorCallback callback) {
         Message m = mCallbacksHandler.obtainMessage(CALLBACK_REMOVE, callback);
         m.arg1 = monitoringType;
         mCallbacksHandler.sendMessage(m);
@@ -477,13 +509,25 @@
                             "Location: " + geofenceTransition.mLocation + ":" + mGeofences);
 
                     try {
-                        callback.onGeofenceChange(
+                        callback.onGeofenceTransition(
                                 geofenceTransition.mGeofenceId, geofenceTransition.mTransition,
                                 geofenceTransition.mLocation, geofenceTransition.mTimestamp,
                                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE);
                     } catch (RemoteException e) {}
                     releaseWakeLock();
                     break;
+                case GEOFENCE_CALLBACK_BINDER_DIED:
+                   // Find all geofences associated with this callback and remove them.
+                   callback = (IGeofenceHardwareCallback) (msg.obj);
+                   if (DEBUG) Log.d(TAG, "Geofence callback reaped:" + callback);
+                   int monitoringType = msg.arg1;
+                   for (int i = 0; i < mGeofences.size(); i++) {
+                        if (mGeofences.valueAt(i).equals(callback)) {
+                            geofenceId = mGeofences.keyAt(i);
+                            removeGeofence(mGeofences.keyAt(i), monitoringType);
+                            mGeofences.remove(geofenceId);
+                        }
+                   }
             }
         }
     };
@@ -493,8 +537,8 @@
         @Override
         public void handleMessage(Message msg) {
             int monitoringType;
-            ArrayList<IGeofenceHardwareCallback> callbackList;
-            IGeofenceHardwareCallback callback;
+            ArrayList<IGeofenceHardwareMonitorCallback> callbackList;
+            IGeofenceHardwareMonitorCallback callback;
 
             switch (msg.what) {
                 case GPS_GEOFENCE_STATUS:
@@ -508,7 +552,7 @@
 
                     if (DEBUG) Log.d(TAG, "MonitoringSystemChangeCallback: GPS : " + available);
 
-                    for (IGeofenceHardwareCallback c: callbackList) {
+                    for (IGeofenceHardwareMonitorCallback c: callbackList) {
                         try {
                             c.onMonitoringSystemChange(
                                     GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, available,
@@ -519,22 +563,71 @@
                     break;
                 case CALLBACK_ADD:
                     monitoringType = msg.arg1;
-                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
                     callbackList = mCallbacks[monitoringType];
                     if (callbackList == null) {
-                        callbackList = new ArrayList<IGeofenceHardwareCallback>();
+                        callbackList = new ArrayList<IGeofenceHardwareMonitorCallback>();
                         mCallbacks[monitoringType] = callbackList;
                     }
                     if (!callbackList.contains(callback)) callbackList.add(callback);
                     break;
                 case CALLBACK_REMOVE:
                     monitoringType = msg.arg1;
-                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
                     callbackList = mCallbacks[monitoringType];
                     if (callbackList != null) {
                         callbackList.remove(callback);
                     }
                     break;
+                case MONITOR_CALLBACK_BINDER_DIED:
+                    callback = (IGeofenceHardwareMonitorCallback) msg.obj;
+                    if (DEBUG) Log.d(TAG, "Monitor callback reaped:" + callback);
+                    callbackList = mCallbacks[msg.arg1];
+                    if (callbackList != null && callbackList.contains(callback)) {
+                        callbackList.remove(callback);
+                    }
+            }
+        }
+    };
+
+    // All operations on mReaper
+    private Handler mReaperHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            Reaper r;
+            IGeofenceHardwareCallback callback;
+            IGeofenceHardwareMonitorCallback monitorCallback;
+            int monitoringType;
+
+            switch (msg.what) {
+                case REAPER_GEOFENCE_ADDED:
+                    callback = (IGeofenceHardwareCallback) msg.obj;
+                    monitoringType = msg.arg1;
+                    r = new Reaper(callback, monitoringType);
+                    if (!mReapers.contains(r)) {
+                        mReapers.add(r);
+                        IBinder b = callback.asBinder();
+                        try {
+                            b.linkToDeath(r, 0);
+                        } catch (RemoteException e) {}
+                    }
+                    break;
+                case REAPER_MONITOR_CALLBACK_ADDED:
+                    monitorCallback = (IGeofenceHardwareMonitorCallback) msg.obj;
+                    monitoringType = msg.arg1;
+
+                    r = new Reaper(monitorCallback, monitoringType);
+                    if (!mReapers.contains(r)) {
+                        mReapers.add(r);
+                        IBinder b = monitorCallback.asBinder();
+                        try {
+                            b.linkToDeath(r, 0);
+                        } catch (RemoteException e) {}
+                    }
+                    break;
+                case REAPER_REMOVED:
+                    r = (Reaper) msg.obj;
+                    mReapers.remove(r);
             }
         }
     };
@@ -567,6 +660,57 @@
         return RESOLUTION_LEVEL_NONE;
     }
 
+    class Reaper implements IBinder.DeathRecipient {
+        private IGeofenceHardwareMonitorCallback mMonitorCallback;
+        private IGeofenceHardwareCallback mCallback;
+        private int mMonitoringType;
+
+        Reaper(IGeofenceHardwareCallback c, int monitoringType) {
+            mCallback = c;
+            mMonitoringType = monitoringType;
+        }
+
+        Reaper(IGeofenceHardwareMonitorCallback c, int monitoringType) {
+            mMonitorCallback = c;
+            mMonitoringType = monitoringType;
+        }
+
+        @Override
+        public void binderDied() {
+            Message m;
+            if (mCallback != null) {
+                m = mGeofenceHandler.obtainMessage(GEOFENCE_CALLBACK_BINDER_DIED, mCallback);
+                m.arg1 = mMonitoringType;
+                mGeofenceHandler.sendMessage(m);
+            } else if (mMonitorCallback != null) {
+                m = mCallbacksHandler.obtainMessage(MONITOR_CALLBACK_BINDER_DIED, mMonitorCallback);
+                m.arg1 = mMonitoringType;
+                mCallbacksHandler.sendMessage(m);
+            }
+            Message reaperMessage = mReaperHandler.obtainMessage(REAPER_REMOVED, this);
+            mReaperHandler.sendMessage(reaperMessage);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 17;
+            result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
+            result = 31 * result + (mMonitorCallback != null ? mMonitorCallback.hashCode() : 0);
+            result = 31 * result + mMonitoringType;
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) return false;
+            if (obj == this) return true;
+
+            Reaper rhs = (Reaper) obj;
+            return rhs.mCallback == mCallback && rhs.mMonitorCallback == mMonitorCallback &&
+                    rhs.mMonitoringType == mMonitoringType;
+        }
+    }
+
     int getAllowedResolutionLevel(int pid, int uid) {
         if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                 pid, uid) == PackageManager.PERMISSION_GRANTED) {
diff --git a/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
new file mode 100644
index 0000000..b8e927e
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareMonitorCallback.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.location.Location;
+
+/**
+ * The callback class associated with the status change of hardware montiors
+ * in {@link GeofenceHardware}
+ */
+public abstract class GeofenceHardwareMonitorCallback {
+    /**
+     * The callback called when the state of a monitoring system changes.
+     * {@link GeofenceHardware#MONITORING_TYPE_GPS_HARDWARE} is an example of a
+     * monitoring system
+     *
+     * @param monitoringType The type of the monitoring system.
+     * @param available Indicates whether the system is currenty available or not.
+     * @param location The last known location according to the monitoring system.
+     */
+    public void onMonitoringSystemChange(int monitoringType, boolean available, Location location) {
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareRequest.java b/core/java/android/hardware/location/GeofenceHardwareRequest.java
new file mode 100644
index 0000000..6e7b592
--- /dev/null
+++ b/core/java/android/hardware/location/GeofenceHardwareRequest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.location.Location;
+
+/**
+ * This class represents the characteristics of the geofence.
+ *
+ * <p> Use this in conjunction with {@link GeofenceHardware} APIs.
+ */
+
+public final class GeofenceHardwareRequest {
+    static final int GEOFENCE_TYPE_CIRCLE = 0;
+    private int mType;
+    private double mLatitude;
+    private double mLongitude;
+    private double mRadius;
+    private int mLastTransition = GeofenceHardware.GEOFENCE_UNCERTAIN;
+    private int mUnknownTimer = 30000; // 30 secs
+    private int mMonitorTransitions = GeofenceHardware.GEOFENCE_UNCERTAIN |
+        GeofenceHardware.GEOFENCE_ENTERED | GeofenceHardware.GEOFENCE_EXITED;
+    private int mNotificationResponsiveness = 5000; // 5 secs
+
+    private void setCircularGeofence(double latitude, double longitude, double radius) {
+        mLatitude = latitude;
+        mLongitude = longitude;
+        mRadius = radius;
+        mType  = GEOFENCE_TYPE_CIRCLE;
+    }
+
+    /**
+     * Create a circular geofence.
+     *
+     * @param latitude Latitude of the geofence
+     * @param longitude Longitude of the geofence
+     * @param radius Radius of the geofence (in meters)
+     */
+    public static GeofenceHardwareRequest createCircularGeofence(double latitude,
+            double longitude, double radius) {
+        GeofenceHardwareRequest geofenceRequest = new GeofenceHardwareRequest();
+        geofenceRequest.setCircularGeofence(latitude, longitude, radius);
+        return geofenceRequest;
+    }
+
+    /**
+     * Set the last known transition of the geofence.
+     *
+     * @param lastTransition The current state of the geofence. Can be one of
+     *        {@link GeofenceHardware#GEOFENCE_ENTERED}, {@link GeofenceHardware#GEOFENCE_EXITED},
+     *        {@link GeofenceHardware#GEOFENCE_UNCERTAIN}.
+     */
+    public void setLastTransition(int lastTransition) {
+        mLastTransition = lastTransition;
+    }
+
+    /**
+     * Set the unknown timer for this geofence.
+     *
+     * @param unknownTimer  The time limit after which the
+     *        {@link GeofenceHardware#GEOFENCE_UNCERTAIN} transition
+     *        should be triggered. This paramter is defined in milliseconds.
+     */
+    public void setUnknownTimer(int unknownTimer) {
+        mUnknownTimer = unknownTimer;
+    }
+
+    /**
+     * Set the transitions to be monitored.
+     *
+     * @param monitorTransitions Bitwise OR of {@link GeofenceHardware#GEOFENCE_ENTERED},
+     *        {@link GeofenceHardware#GEOFENCE_EXITED}, {@link GeofenceHardware#GEOFENCE_UNCERTAIN}
+     */
+    public void setMonitorTransitions(int monitorTransitions) {
+        mMonitorTransitions = monitorTransitions;
+    }
+
+    /**
+     * Set the notification responsiveness of the geofence.
+     *
+     * @param notificationResponsiveness (milliseconds) Defines the best-effort description
+     *        of how soon should the callback be called when the transition
+     *        associated with the Geofence is triggered. For instance, if
+     *        set to 1000 millseconds with {@link GeofenceHardware#GEOFENCE_ENTERED},
+     *        the callback will be called 1000 milliseconds within entering
+     *        the geofence.
+     */
+    public void setNotificationResponsiveness(int notificationResponsiveness) {
+       mNotificationResponsiveness = notificationResponsiveness;
+    }
+
+    /**
+     * Returns the latitude of this geofence.
+     */
+    public double getLatitude() {
+        return mLatitude;
+    }
+
+    /**
+     * Returns the longitude of this geofence.
+     */
+    public double getLongitude() {
+        return mLongitude;
+    }
+
+    /**
+     * Returns the radius of this geofence.
+     */
+    public double getRadius() {
+        return mRadius;
+    }
+
+    /**
+     * Returns transitions monitored for this geofence.
+     */
+    public int getMonitorTransitions() {
+        return mMonitorTransitions;
+    }
+
+    /**
+     * Returns the unknownTimer of this geofence.
+     */
+    public int getUnknownTimer() {
+        return mUnknownTimer;
+    }
+
+    /**
+     * Returns the notification responsiveness of this geofence.
+     */
+    public int getNotificationResponsiveness() {
+        return mNotificationResponsiveness;
+    }
+
+    /**
+     * Returns the last transition of this geofence.
+     */
+    public int getLastTransition() {
+        return mLastTransition;
+    }
+
+    int getType() {
+        return mType;
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index 0eccee6..3bc70ee 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -68,23 +68,28 @@
             mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
         }
 
-        public int[] getMonitoringTypesAndStatus() {
+        public int[] getMonitoringTypes() {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
-            return mGeofenceHardwareImpl.getMonitoringTypesAndStatus();
+            return mGeofenceHardwareImpl.getMonitoringTypes();
         }
 
-        public boolean addCircularFence(int id, double lat, double longitude, double radius,
-                int lastTransition, int monitorTransitions, int
-                notificationResponsiveness, int unknownTimer, int monitoringType,
-                IGeofenceHardwareCallback callback) {
+        public int getStatusOfMonitoringType(int monitoringType) {
+            mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
+                    "Location Hardware permission not granted to access hardware geofence");
+
+            return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
+        }
+        public boolean addCircularFence(int id, int monitoringType, double lat, double longitude,
+                double radius, int lastTransition, int monitorTransitions, int
+                notificationResponsiveness, int unknownTimer, IGeofenceHardwareCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
-            return mGeofenceHardwareImpl.addCircularFence(id, lat, longitude, radius,
-                    lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer,
-                    monitoringType, callback);
+            return mGeofenceHardwareImpl.addCircularFence(id, monitoringType, lat, longitude,
+                    radius, lastTransition, monitorTransitions, notificationResponsiveness,
+                    unknownTimer, callback);
         }
 
         public boolean removeGeofence(int id, int monitoringType) {
@@ -103,16 +108,16 @@
             return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
         }
 
-        public boolean resumeGeofence(int id, int monitorTransitions, int monitoringType) {
+        public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
             checkPermission(Binder.getCallingPid(), Binder.getCallingUid(), monitoringType);
-            return mGeofenceHardwareImpl.resumeGeofence(id, monitorTransitions, monitoringType);
+            return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
         }
 
         public boolean registerForMonitorStateChangeCallback(int monitoringType,
-                IGeofenceHardwareCallback callback) {
+                IGeofenceHardwareMonitorCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
@@ -122,7 +127,7 @@
         }
 
         public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-                IGeofenceHardwareCallback callback) {
+                IGeofenceHardwareMonitorCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
diff --git a/core/java/android/hardware/location/IGeofenceHardware.aidl b/core/java/android/hardware/location/IGeofenceHardware.aidl
index 4ba02b8..6900070 100644
--- a/core/java/android/hardware/location/IGeofenceHardware.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardware.aidl
@@ -18,19 +18,21 @@
 
 import android.location.IGpsGeofenceHardware;
 import android.hardware.location.IGeofenceHardwareCallback;
+import android.hardware.location.IGeofenceHardwareMonitorCallback;
 
 /** @hide */
 interface IGeofenceHardware {
     void setGpsGeofenceHardware(in IGpsGeofenceHardware service);
-    int[] getMonitoringTypesAndStatus();
-    boolean addCircularFence(int id, double lat, double longitude, double radius,
-            int lastTransition, int monitorTransitions, int notificationResponsiveness,
-            int unknownTimer, int monitoringType, in IGeofenceHardwareCallback callback);
+    int[] getMonitoringTypes();
+    int getStatusOfMonitoringType(int monitoringType);
+    boolean addCircularFence(int id,  int monitoringType, double lat, double longitude,
+            double radius, int lastTransition, int monitorTransitions,
+            int notificationResponsiveness, int unknownTimer,in IGeofenceHardwareCallback callback);
     boolean removeGeofence(int id, int monitoringType);
     boolean pauseGeofence(int id, int monitoringType);
-    boolean resumeGeofence(int id, int monitorTransitions, int monitoringType);
+    boolean resumeGeofence(int id, int monitoringType, int monitorTransitions);
     boolean registerForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback);
+            IGeofenceHardwareMonitorCallback callback);
     boolean unregisterForMonitorStateChangeCallback(int monitoringType,
-            IGeofenceHardwareCallback callback);
+            IGeofenceHardwareMonitorCallback callback);
 }
diff --git a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
index 678fc49..3a8f430 100644
--- a/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
+++ b/core/java/android/hardware/location/IGeofenceHardwareCallback.aidl
@@ -20,8 +20,7 @@
 
 /** @hide */
 oneway interface IGeofenceHardwareCallback {
-   void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
-   void onGeofenceChange(int geofenceId, int transition, in Location location,
+   void onGeofenceTransition(int geofenceId, int transition, in Location location,
             long timestamp, int monitoringType);
    void onGeofenceAdd(int geofenceId, int status);
    void onGeofenceRemove(int geofenceId, int status);
diff --git a/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
new file mode 100644
index 0000000..0b6e04b
--- /dev/null
+++ b/core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.location.Location;
+
+/** @hide */
+oneway interface IGeofenceHardwareMonitorCallback {
+   void onMonitoringSystemChange(int monitoringType, boolean available, in Location location);
+}
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 0856e27..b2034b2 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -107,6 +107,11 @@
      * {@link UsbConstants#USB_DIR_OUT}, then the transfer is a write,
      * and if it is {@link UsbConstants#USB_DIR_IN}, then the transfer
      * is a read.
+     * <p>
+     * This method transfers data starting from index 0 in the buffer.
+     * To specify a different offset, use
+     * {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}.
+     * </p>
      *
      * @param requestType request type for this transaction
      * @param request request ID for this transaction
@@ -118,11 +123,7 @@
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
-     *
-     * @deprecated Use {@link #controlTransfer(int, int, int, int, byte[], int, int, int)}
-     * which accepts a buffer start index.
      */
-    @Deprecated
     public int controlTransfer(int requestType, int request, int value,
             int index, byte[] buffer, int length, int timeout) {
         return controlTransfer(requestType, request, value, index, buffer, 0, length, timeout);
@@ -142,22 +143,27 @@
      * @param index index field for this transaction
      * @param buffer buffer for data portion of transaction,
      * or null if no data needs to be sent or received
-     * @param start the index of the first byte in the buffer to send or receive
+     * @param offset the index of the first byte in the buffer to send or receive
      * @param length the length of the data to send or receive
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
      */
     public int controlTransfer(int requestType, int request, int value, int index,
-            byte[] buffer, int start, int length, int timeout) {
-        checkBounds(buffer, start, length);
+            byte[] buffer, int offset, int length, int timeout) {
+        checkBounds(buffer, offset, length);
         return native_control_request(requestType, request, value, index,
-                buffer, start, length, timeout);
+                buffer, offset, length, timeout);
     }
 
     /**
      * Performs a bulk transaction on the given endpoint.
-     * The direction of the transfer is determined by the direction of the endpoint
+     * The direction of the transfer is determined by the direction of the endpoint.
+     * <p>
+     * This method transfers data starting from index 0 in the buffer.
+     * To specify a different offset, use
+     * {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}.
+     * </p>
      *
      * @param endpoint the endpoint for this transaction
      * @param buffer buffer for data to send or receive
@@ -165,11 +171,7 @@
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
-     *
-     * @deprecated Use {@link #bulkTransfer(UsbEndpoint, byte[], int, int, int)}
-     * which accepts a buffer start index.
      */
-    @Deprecated
     public int bulkTransfer(UsbEndpoint endpoint,
             byte[] buffer, int length, int timeout) {
         return bulkTransfer(endpoint, buffer, 0, length, timeout);
@@ -177,20 +179,20 @@
 
     /**
      * Performs a bulk transaction on the given endpoint.
-     * The direction of the transfer is determined by the direction of the endpoint
+     * The direction of the transfer is determined by the direction of the endpoint.
      *
      * @param endpoint the endpoint for this transaction
      * @param buffer buffer for data to send or receive
-     * @param start the index of the first byte in the buffer to send or receive
+     * @param offset the index of the first byte in the buffer to send or receive
      * @param length the length of the data to send or receive
      * @param timeout in milliseconds
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
      */
     public int bulkTransfer(UsbEndpoint endpoint,
-            byte[] buffer, int start, int length, int timeout) {
-        checkBounds(buffer, start, length);
-        return native_bulk_request(endpoint.getAddress(), buffer, start, length, timeout);
+            byte[] buffer, int offset, int length, int timeout) {
+        checkBounds(buffer, offset, length);
+        return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
     }
 
     /**
@@ -235,9 +237,9 @@
     private native boolean native_claim_interface(int interfaceID, boolean force);
     private native boolean native_release_interface(int interfaceID);
     private native int native_control_request(int requestType, int request, int value,
-            int index, byte[] buffer, int start, int length, int timeout);
+            int index, byte[] buffer, int offset, int length, int timeout);
     private native int native_bulk_request(int endpoint, byte[] buffer,
-            int start, int length, int timeout);
+            int offset, int length, int timeout);
     private native UsbRequest native_request_wait();
     private native String native_get_serial();
 }
diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java
index 2b359eb..ab4cd9b 100644
--- a/core/java/android/net/DhcpInfo.java
+++ b/core/java/android/net/DhcpInfo.java
@@ -22,8 +22,7 @@
 
 /**
  * A simple object for retrieving the results of a DHCP request.
- * @deprecated - use LinkProperties - To be removed 11/2013
- * STOPSHIP - make sure we expose LinkProperties through ConnectivityManager
+ * @deprecated - use LinkProperties - To be removed 11/2014
  */
 public class DhcpInfo implements Parcelable {
     public int ipAddress;
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index d9846ec..61eef1f 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -51,6 +51,7 @@
     private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
 
     private static UserEnvironment sCurrentUser;
+    private static boolean sUserRequired;
 
     private static final Object sLock = new Object();
 
@@ -223,7 +224,7 @@
      * @hide
      */
     public static File getMediaStorageDirectory() {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getMediaStorageDirectory();
     }
 
@@ -318,7 +319,7 @@
      * @see #isExternalStorageRemovable()
      */
     public static File getExternalStorageDirectory() {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageDirectory();
     }
 
@@ -465,7 +466,7 @@
      * using it such as with {@link File#mkdirs File.mkdirs()}.
      */
     public static File getExternalStoragePublicDirectory(String type) {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStoragePublicDirectory(type);
     }
 
@@ -474,7 +475,7 @@
      * @hide
      */
     public static File getExternalStorageAndroidDataDir() {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageAndroidDataDir();
     }
     
@@ -483,7 +484,7 @@
      * @hide
      */
     public static File getExternalStorageAppDataDirectory(String packageName) {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageAppDataDirectory(packageName);
     }
     
@@ -492,7 +493,7 @@
      * @hide
      */
     public static File getExternalStorageAppMediaDirectory(String packageName) {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageAppMediaDirectory(packageName);
     }
     
@@ -501,7 +502,7 @@
      * @hide
      */
     public static File getExternalStorageAppObbDirectory(String packageName) {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageAppObbDirectory(packageName);
     }
     
@@ -510,7 +511,7 @@
      * @hide
      */
     public static File getExternalStorageAppFilesDirectory(String packageName) {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageAppFilesDirectory(packageName);
     }
 
@@ -519,7 +520,7 @@
      * @hide
      */
     public static File getExternalStorageAppCacheDirectory(String packageName) {
-        throwIfSystem();
+        throwIfUserRequired();
         return sCurrentUser.getExternalStorageAppCacheDirectory(packageName);
     }
     
@@ -650,9 +651,15 @@
         }
     }
 
-    private static void throwIfSystem() {
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
+    /** {@hide} */
+    public static void setUserRequired(boolean userRequired) {
+        sUserRequired = userRequired;
+    }
+
+    private static void throwIfUserRequired() {
+        if (sUserRequired) {
+            Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
+                    new Throwable());
         }
     }
 
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 94de448..14d8f07 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -413,27 +413,32 @@
 
     /**
      * Runs the specified task synchronously.
-     *
+     * <p>
      * If the current thread is the same as the handler thread, then the runnable
      * runs immediately without being enqueued.  Otherwise, posts the runnable
      * to the handler and waits for it to complete before returning.
-     *
+     * </p><p>
      * This method is dangerous!  Improper use can result in deadlocks.
      * Never call this method while any locks are held or use it in a
      * possibly re-entrant manner.
-     *
+     * </p><p>
      * This method is occasionally useful in situations where a background thread
      * must synchronously await completion of a task that must run on the
      * handler's thread.  However, this problem is often a symptom of bad design.
      * Consider improving the design (if possible) before resorting to this method.
-     *
+     * </p><p>
      * One example of where you might want to use this method is when you just
      * set up a Handler thread and need to perform some initialization steps on
      * it before continuing execution.
-     *
+     * </p><p>
      * If timeout occurs then this method returns <code>false</code> but the runnable
      * will remain posted on the handler and may already be in progress or
      * complete at a later time.
+     * </p><p>
+     * When using this method, be sure to use {@link Looper#quitSafely} when
+     * quitting the looper.  Otherwise {@link #runWithScissors} may hang indefinitely.
+     * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
+     * </p>
      *
      * @param r The Runnable that will be executed synchronously.
      * @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index daf1f59..2904105 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -48,6 +48,7 @@
     protected void onLooperPrepared() {
     }
 
+    @Override
     public void run() {
         mTid = Process.myTid();
         Looper.prepare();
@@ -83,12 +84,25 @@
         }
         return mLooper;
     }
-    
+
     /**
-     * Ask the currently running looper to quit.  If the thread has not
-     * been started or has finished (that is if {@link #getLooper} returns
-     * null), then false is returned.  Otherwise the looper is asked to
-     * quit and true is returned.
+     * Quits the handler thread's looper.
+     * <p>
+     * Causes the handler thread's looper to terminate without processing any
+     * more messages in the message queue.
+     * </p><p>
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p><p class="note">
+     * Using this method may be unsafe because some messages may not be delivered
+     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
+     * that all pending work is completed in an orderly manner.
+     * </p>
+     *
+     * @return True if the looper looper has been asked to quit or false if the
+     * thread had not yet started running.
+     *
+     * @see #quitSafely
      */
     public boolean quit() {
         Looper looper = getLooper();
@@ -98,7 +112,34 @@
         }
         return false;
     }
-    
+
+    /**
+     * Quits the handler thread's looper safely.
+     * <p>
+     * Causes the handler thread's looper to terminate as soon as all remaining messages
+     * in the message queue that are already due to be delivered have been handled.
+     * Pending delayed messages with due times in the future will not be delivered.
+     * </p><p>
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p><p>
+     * If the thread has not been started or has finished (that is if
+     * {@link #getLooper} returns null), then false is returned.
+     * Otherwise the looper is asked to quit and true is returned.
+     * </p>
+     *
+     * @return True if the looper looper has been asked to quit or false if the
+     * thread had not yet started running.
+     */
+    public boolean quitSafely() {
+        Looper looper = getLooper();
+        if (looper != null) {
+            looper.quitSafely();
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Returns the identifier of this thread. See Process.myTid().
      */
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 2e8092a..a11358a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -42,7 +42,8 @@
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
     void setUserRestrictions(in Bundle restrictions, int userHandle);
-    void setApplicationRestrictions(in String packageName, in List<RestrictionEntry> entries,
+    void setApplicationRestrictions(in String packageName, in Bundle restrictions,
             int userHandle);
-    List<RestrictionEntry> getApplicationRestrictions(in String packageName, int userHandle);
+    Bundle getApplicationRestrictions(in String packageName);
+    Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
 }
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index fa28765..d5cf771 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -202,18 +202,37 @@
     /**
      * Quits the looper.
      * <p>
-     * Causes the {@link #loop} method to terminate as soon as all remaining messages
-     * in the message queue that are already due to be delivered have been handled.
-     * However delayed messages with due times in the future may not be handled before
-     * the loop terminates.
+     * Causes the {@link #loop} method to terminate without processing any
+     * more messages in the message queue.
      * </p><p>
-     * Any attempt to post messages to the queue after {@link #quit} has been called
-     * will fail.  For example, the {@link Handler#sendMessage(Message)} method will
-     * return false when the looper is being terminated.
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p><p class="note">
+     * Using this method may be unsafe because some messages may not be delivered
+     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
+     * that all pending work is completed in an orderly manner.
      * </p>
+     *
+     * @see #quitSafely
      */
     public void quit() {
-        mQueue.quit();
+        mQueue.quit(false);
+    }
+
+    /**
+     * Quits the looper safely.
+     * <p>
+     * Causes the {@link #loop} method to terminate as soon as all remaining messages
+     * in the message queue that are already due to be delivered have been handled.
+     * However pending delayed messages with due times in the future will not be
+     * delivered before the loop terminates.
+     * </p><p>
+     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
+     * For example, the {@link Handler#sendMessage(Message)} method will return false.
+     * </p>
+     */
+    public void quitSafely() {
+        mQueue.quit(true);
     }
 
     /**
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index c058bfc..bf7e5ca 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -219,7 +219,7 @@
         }
     }
 
-    void quit() {
+    void quit(boolean safe) {
         if (!mQuitAllowed) {
             throw new RuntimeException("Main thread not allowed to quit.");
         }
@@ -229,6 +229,12 @@
                 return;
             }
             mQuiting = true;
+
+            if (safe) {
+                removeAllFutureMessagesLocked();
+            } else {
+                removeAllMessagesLocked();
+            }
         }
         nativeWake(mPtr);
     }
@@ -473,4 +479,42 @@
             }
         }
     }
+
+    private void removeAllMessagesLocked() {
+        Message p = mMessages;
+        while (p != null) {
+            Message n = p.next;
+            p.recycle();
+            p = n;
+        }
+        mMessages = null;
+    }
+
+    private void removeAllFutureMessagesLocked() {
+        final long now = SystemClock.uptimeMillis();
+        Message p = mMessages;
+        if (p != null) {
+            if (p.when > now) {
+                removeAllMessagesLocked();
+            } else {
+                Message n;
+                for (;;) {
+                    n = p.next;
+                    if (n == null) {
+                        return;
+                    }
+                    if (n.when > now) {
+                        break;
+                    }
+                    p = n;
+                }
+                p.next = null;
+                do {
+                    p = n;
+                    n = p.next;
+                    p.recycle();
+                } while (n != null);
+            }
+        }
+    }
 }
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index 60ec0d7..2314057 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -57,9 +57,9 @@
     }
 
     /**
-     * The size, in bytes, of a block on the file system. This corresponds to
-     * the Unix {@code statfs.f_bsize} field.
+     * @deprecated Use {@link #getBlockSizeLong()} instead.
      */
+    @Deprecated
     public int getBlockSize() {
         return (int) mStat.f_bsize;
     }
@@ -73,27 +73,25 @@
     }
 
     /**
-     * The total number of blocks on the file system. This corresponds to the
-     * Unix {@code statfs.f_blocks} field.
+     * @deprecated Use {@link #getBlockCountLong()} instead.
      */
+    @Deprecated
     public int getBlockCount() {
         return (int) mStat.f_blocks;
     }
 
     /**
-     * The size, in bytes, of a block on the file system. This corresponds to
-     * the Unix {@code statfs.f_bsize} field.
+     * The total number of blocks on the file system. This corresponds to the
+     * Unix {@code statfs.f_blocks} field.
      */
     public long getBlockCountLong() {
         return mStat.f_blocks;
     }
 
     /**
-     * The total number of blocks that are free on the file system, including
-     * reserved blocks (that are not available to normal applications). This
-     * corresponds to the Unix {@code statfs.f_bfree} field. Most applications
-     * will want to use {@link #getAvailableBlocks()} instead.
+     * @deprecated Use {@link #getFreeBlocksLong()} instead.
      */
+    @Deprecated
     public int getFreeBlocks() {
         return (int) mStat.f_bfree;
     }
@@ -109,17 +107,18 @@
     }
 
     /**
-     * The number of bytes that are free on the file system, including
-     * reserved blocks (that are not available to normal applications).
+     * The number of bytes that are free on the file system, including reserved
+     * blocks (that are not available to normal applications). Most applications
+     * will want to use {@link #getAvailableBytes()} instead.
      */
     public long getFreeBytes() {
         return mStat.f_bfree * mStat.f_bsize;
     }
 
     /**
-     * The number of blocks that are free on the file system and available to
-     * applications. This corresponds to the Unix {@code statfs.f_bavail} field.
+     * @deprecated Use {@link #getAvailableBlocksLong()} instead.
      */
+    @Deprecated
     public int getAvailableBlocks() {
         return (int) mStat.f_bavail;
     }
@@ -139,4 +138,11 @@
     public long getAvailableBytes() {
         return mStat.f_bavail * mStat.f_bsize;
     }
+
+    /**
+     * The total number of bytes supported by the file system.
+     */
+    public long getTotalBytes() {
+        return mStat.f_blocks * mStat.f_bsize;
+    }
 }
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 617f490..3307a8c 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -79,6 +79,7 @@
     private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
     private static native void nativeSetAppTracingAllowed(boolean allowed);
+    private static native void nativeSetTracingEnabled(boolean allowed);
 
     static {
         // We configure two separate change callbacks, one in Trace.cpp and one here.  The
@@ -115,10 +116,6 @@
      */
     private static long cacheEnabledTags() {
         long tags = nativeGetEnabledTags();
-        if (tags == TRACE_TAG_NOT_READY) {
-            Log.w(TAG, "Unexpected value from nativeGetEnabledTags: " + tags);
-            // keep going
-        }
         sEnabledTags = tags;
         return tags;
     }
@@ -169,6 +166,22 @@
     }
 
     /**
+     * Set whether tracing is enabled in this process.  Tracing is disabled shortly after Zygote
+     * initializes and re-enabled after processes fork from Zygote.  This is done because Zygote
+     * has no way to be notified about changes to the tracing tags, and if Zygote ever reads and
+     * caches the tracing tags, forked processes will inherit those stale tags.
+     *
+     * @hide
+     */
+    public static void setTracingEnabled(boolean enabled) {
+        nativeSetTracingEnabled(enabled);
+
+        // Setting whether tracing is enabled may change the tags, so we update the cached tags
+        // here.
+        cacheEnabledTags();
+    }
+
+    /**
      * Writes a trace message to indicate that a given section of code has
      * begun. Must be followed by a call to {@link #traceEnd} using the same
      * tag.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index e580e2b..df065e9 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -142,6 +142,7 @@
 
     private static UserManager sInstance = null;
 
+    /** @hide */
     public synchronized static UserManager get(Context context) {
         if (sInstance == null) {
             sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -578,13 +579,29 @@
         return -1;
     }
 
+    /**
+     * Returns a Bundle containing any saved application restrictions for this user, for the
+     * given package name. Only an application with this package name can call this method.
+     * @param packageName the package name of the calling application
+     * @return a Bundle with the restrictions as key/value pairs, or null if there are no
+     * saved restrictions. The values can be of type Boolean, String or String[], depending
+     * on the restriction type, as defined by the application.
+     */
+    public Bundle getApplicationRestrictions(String packageName) {
+        try {
+            return mService.getApplicationRestrictions(packageName);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get application restrictions for package " + packageName);
+        }
+        return null;
+    }
 
     /**
      * @hide
      */
-    public List<RestrictionEntry> getApplicationRestrictions(String packageName, UserHandle user) {
+    public Bundle getApplicationRestrictions(String packageName, UserHandle user) {
         try {
-            return mService.getApplicationRestrictions(packageName, user.getIdentifier());
+            return mService.getApplicationRestrictionsForUser(packageName, user.getIdentifier());
         } catch (RemoteException re) {
             Log.w(TAG, "Could not get application restrictions for user " + user.getIdentifier());
         }
@@ -594,10 +611,10 @@
     /**
      * @hide
      */
-    public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+    public void setApplicationRestrictions(String packageName, Bundle restrictions,
             UserHandle user) {
         try {
-            mService.setApplicationRestrictions(packageName, entries, user.getIdentifier());
+            mService.setApplicationRestrictions(packageName, restrictions, user.getIdentifier());
         } catch (RemoteException re) {
             Log.w(TAG, "Could not set application restrictions for user " + user.getIdentifier());
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 88ee414..4de5933 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -714,6 +714,17 @@
      */
     public static final String EXTRA_AUTHORITIES = "authorities";
 
+    /**
+     * Activity Extra: Limit available options in launched activity based on the given account
+     * types.
+     * <p>
+     * This can be passed as an extra field in an Activity Intent with one or more account types
+     * as a String[]. This field is used by some intents to alter the behavior of the called
+     * activity.
+     * <p>
+     * Example: The {@link #ACTION_ADD_ACCOUNT} intent restricts the account types to the specified
+     * list.
+     */
     public static final String EXTRA_ACCOUNT_TYPES = "account_types";
 
     public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
@@ -3260,6 +3271,7 @@
         /**
          * This preference contains the string that shows for owner info on LockScreen.
          * @hide
+         * @deprecated
          */
         public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info";
 
@@ -3287,6 +3299,7 @@
         /**
          * This preference enables showing the owner info on LockScreen.
          * @hide
+         * @deprecated
          */
         public static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
             "lock_screen_owner_info_enabled";
@@ -4102,9 +4115,7 @@
             MOUNT_UMS_AUTOSTART,
             MOUNT_UMS_PROMPT,
             MOUNT_UMS_NOTIFY_ENABLED,
-            UI_NIGHT_MODE,
-            LOCK_SCREEN_OWNER_INFO,
-            LOCK_SCREEN_OWNER_INFO_ENABLED
+            UI_NIGHT_MODE
         };
 
         /**
diff --git a/core/java/android/text/bidi/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
similarity index 78%
rename from core/java/android/text/bidi/BidiFormatter.java
rename to core/java/android/text/BidiFormatter.java
index 7a08213..3fab35b 100644
--- a/core/java/android/text/bidi/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -14,18 +14,14 @@
  * limitations under the License.
  */
 
-package android.text.bidi;
+package android.text;
 
-import android.text.TextDirectionHeuristic;
-import android.text.TextDirectionHeuristics;
-import android.text.TextUtils;
 import android.view.View;
 
 import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
 
 import java.util.Locale;
 
-
 /**
  * Utility class for formatting text for display in a potentially opposite-directionality context
  * without garbling. The directionality of the context is set at formatter creation and the
@@ -34,14 +30,12 @@
  * <p>
  * 1. Bidi Wrapping
  * When text in one language is mixed into a document in another, opposite-directionality language,
- * e.g. when an English business name is embedded in a Hebrew web page, both the inserted string
+ * e.g. when an English business name is embedded in some Hebrew text, both the inserted string
  * and the text surrounding it may be displayed incorrectly unless the inserted string is explicitly
  * separated from the surrounding text in a "wrapper" that:
  * <p>
- * - Declares its directionality so that the string is displayed correctly. This can be done in HTML
- *   markup (e.g. a 'span dir="rtl"' element) by {@link #spanWrap} and similar methods, or - only in
- *   contexts where markup can't be used - in Unicode bidi formatting codes by {@link #unicodeWrap}
- *   and similar methods.
+ * - Declares its directionality so that the string is displayed correctly. This can be done in
+ *   Unicode bidi formatting codes by {@link #unicodeWrap} and similar methods.
  * <p>
  * - Isolates the string's directionality, so it does not unduly affect the surrounding content.
  *   Currently, this can only be done using invisible Unicode characters of the same direction as
@@ -80,16 +74,6 @@
  * estimated at run-time. The bidi formatter can do this automatically using the default
  * first-strong estimation algorithm. It can also be configured to use a custom directionality
  * estimation object.
- * <p>
- * 3. Escaping
- * When wrapping plain text - i.e. text that is not already HTML or HTML-escaped - in HTML markup,
- * the text must first be HTML-escaped to prevent XSS attacks and other nasty business. This of
- * course is always true, but the escaping can not be done after the string has already been wrapped
- * in markup, so the bidi formatter also serves as a last chance and includes escaping services.
- * <p>
- * Thus, in a single call, the formatter will escape the input string as specified, determine its
- * directionality, and wrap it as necessary. It is then up to the caller to insert the return value
- * in the output.
  */
 public final class BidiFormatter {
 
@@ -134,36 +118,6 @@
     private static final String RLM_STRING = Character.toString(RLM);
 
     /**
-     * "ltr" string constant.
-     */
-    private static final String LTR_STRING = "ltr";
-
-    /**
-     * "rtl" string constant.
-     */
-    private static final String RTL_STRING = "rtl";
-
-    /**
-     * "dir=\"ltr\"" string constant.
-     */
-    private static final String DIR_LTR_STRING = "dir=\"ltr\"";
-
-    /**
-     * "dir=\"rtl\"" string constant.
-     */
-    private static final String DIR_RTL_STRING = "dir=\"rtl\"";
-
-    /**
-     * "right" string constant.
-     */
-    private static final String RIGHT = "right";
-
-    /**
-     * "left" string constant.
-     */
-    private static final String LEFT = "left";
-
-    /**
      * Empty string constant.
      */
     private static final String EMPTY_STRING = "";
@@ -325,102 +279,21 @@
     }
 
     /**
-     * Returns "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" if it is LTR.
-     *
-     * @param str String whose directionality is to be estimated.
-     * @return "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" otherwise.
-     */
-    public String dirAttrValue(String str) {
-        return dirAttrValue(isRtl(str));
-    }
-
-    /**
-     * Operates like {@link #dirAttrValue(String)}, but uses a given heuristic to estimate the
-     * {@code str}'s directionality.
-     *
-     * @param str String whose directionality is to be estimated.
-     * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
-     *                  directionality.
-     * @return "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" otherwise.
-     */
-    public String dirAttrValue(String str, TextDirectionHeuristic heuristic) {
-        return dirAttrValue(heuristic.isRtl(str, 0, str.length()));
-    }
-
-    /**
-     * Returns "rtl" if the given directionality is RTL, and "ltr" if it is LTR.
-     *
-     * @param isRtl Whether the directionality is RTL or not.
-     * @return "rtl" if the given directionality is RTL, and "ltr" otherwise.
-     */
-    public String dirAttrValue(boolean isRtl) {
-        return isRtl ? RTL_STRING : LTR_STRING;
-    }
-
-    /**
-     * Returns "dir=\"ltr\"" or "dir=\"rtl\"", depending on {@code str}'s estimated directionality,
-     * if it is not the same as the context directionality. Otherwise, returns the empty string.
-     *
-     * @param str String whose directionality is to be estimated.
-     * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
-     *     context; else, the empty string.
-     */
-    public String dirAttr(String str) {
-        return dirAttr(isRtl(str));
-    }
-
-    /**
-     * Operates like {@link #dirAttr(String)}, but uses a given heuristic to estimate the
-     * {@code str}'s directionality.
-     *
-     * @param str String whose directionality is to be estimated.
-     * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
-     *                  directionality.
-     * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
-     *     context; else, the empty string.
-     */
-    public String dirAttr(String str, TextDirectionHeuristic heuristic) {
-        return dirAttr(heuristic.isRtl(str, 0, str.length()));
-    }
-
-    /**
-     * Returns "dir=\"ltr\"" or "dir=\"rtl\"", depending on the given directionality, if it is not
-     * the same as the context directionality. Otherwise, returns the empty string.
-     *
-     * @param isRtl Whether the directionality is RTL or not
-     * @return "dir=\"rtl\"" for RTL text in non-RTL context; "dir=\"ltr\"" for LTR text in non-LTR
-     *     context; else, the empty string.
-     */
-    public String dirAttr(boolean isRtl) {
-        return (isRtl != mIsRtlContext) ? (isRtl ? DIR_RTL_STRING :  DIR_LTR_STRING) : EMPTY_STRING;
-    }
-
-    /**
      * Returns a Unicode bidi mark matching the context directionality (LRM or RLM) if either the
      * overall or the exit directionality of a given string is opposite to the context directionality.
      * Putting this after the string (including its directionality declaration wrapping) prevents it
      * from "sticking" to other opposite-directionality text or a number appearing after it inline
      * with only neutral content in between. Otherwise returns the empty string. While the exit
      * directionality is determined by scanning the end of the string, the overall directionality is
-     * given explicitly in {@code dir}.
-     *
-     * @param str String after which the mark may need to appear.
-     * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
-     *     else, the empty string.
-     */
-    public String markAfter(String str) {
-        return markAfter(str, mDefaultTextDirectionHeuristic);
-    }
-
-    /**
-     * Operates like {@link #markAfter(String)}, but uses a given heuristic to estimate the
-     * {@code str}'s directionality.
+     * given explicitly by a heuristic to estimate the {@code str}'s directionality.
      *
      * @param str String after which the mark may need to appear.
      * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
      *                  directionality.
      * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
      *     else, the empty string.
+     *
+     * @hide
      */
     public String markAfter(String str, TextDirectionHeuristic heuristic) {
         final boolean isRtl = heuristic.isRtl(str, 0, str.length());
@@ -438,28 +311,18 @@
      * Returns a Unicode bidi mark matching the context directionality (LRM or RLM) if either the
      * overall or the entry directionality of a given string is opposite to the context
      * directionality. Putting this before the string (including its directionality declaration
-     * wrapping) prevents it from "sticking" to other opposite-directionality text appearing before it
-     * inline with only neutral content in between. Otherwise returns the empty string. While the
+     * wrapping) prevents it from "sticking" to other opposite-directionality text appearing before
+     * it inline with only neutral content in between. Otherwise returns the empty string. While the
      * entry directionality is determined by scanning the beginning of the string, the overall
-     * directionality is given explicitly in {@code dir}.
-     *
-     * @param str String before which the mark may need to appear.
-     * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
-     *     else, the empty string.
-     */
-    public String markBefore(String str) {
-        return markBefore(str, mDefaultTextDirectionHeuristic);
-    }
-
-    /**
-     * Operates like {@link #markBefore(String)}, but uses a given heuristic to estimate the
-     * {@code str}'s directionality.
+     * directionality is given explicitly by a heuristic to estimate the {@code str}'s directionality.
      *
      * @param str String before which the mark may need to appear.
      * @param heuristic The text direction heuristic that will be used to estimate the {@code str}'s
      *                  directionality.
      * @return LRM for RTL text in LTR context; RLM for LTR text in RTL context;
      *     else, the empty string.
+     *
+     * @hide
      */
     public String markBefore(String str, TextDirectionHeuristic heuristic) {
         final boolean isRtl = heuristic.isRtl(str, 0, str.length());
@@ -474,30 +337,6 @@
     }
 
     /**
-     * Returns the Unicode bidi mark matching the context directionality (LRM for LTR context
-     * directionality, RLM for RTL context directionality).
-     */
-    public String mark() {
-        return mIsRtlContext ? RLM_STRING : LRM_STRING;
-    }
-
-    /**
-     * Returns "right" for RTL context directionality. Otherwise for LTR context directionality
-     * returns "left".
-     */
-    public String startEdge() {
-        return mIsRtlContext ? RIGHT : LEFT;
-    }
-
-    /**
-     * Returns "left" for RTL context directionality. Otherwise for LTR context directionality
-     * returns "right".
-     */
-    public String endEdge() {
-        return mIsRtlContext ? LEFT : RIGHT;
-    }
-
-    /**
      * Estimates the directionality of a string using the default text direction heuristic.
      *
      * @param str String whose directionality is to be estimated.
@@ -509,95 +348,9 @@
     }
 
     /**
-     * Formats a given string of unknown directionality for use in HTML output of the context
-     * directionality, so an opposite-directionality string is neither garbled nor garbles its
-     * surroundings.
-     * <p>
-     * The algorithm: estimates the directionality of the given string using the given heuristic.
-     * If the directionality is known, pass TextDirectionHeuristics.LTR or RTL for heuristic.
-     * In case its directionality doesn't match the context directionality, wraps it with a 'span'
-     * element and adds a "dir" attribute (either 'dir=\"rtl\"' or 'dir=\"ltr\"').
-     * <p>
-     * If {@code isolate}, directionally isolates the string so that it does not garble its
-     * surroundings. Currently, this is done by "resetting" the directionality after the string by
-     * appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when
-     * either the overall directionality or the exit directionality of the string is opposite to that
-     * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and
-     * passing "true" as an argument, also prepends a Unicode bidi mark matching the context
-     * directionality when either the overall directionality or the entry directionality of the
-     * string is opposite to that of the context.
-     * <p>
-     *
-     * @param str The input string.
-     * @param heuristic The algorithm to be used to estimate the string's overall direction.
-     * @param isolate Whether to directionally isolate the string to prevent it from garbling the
-     *     content around it.
-     * @return Input string after applying the above processing.
-     */
-    public String spanWrap(String str, TextDirectionHeuristic heuristic, boolean isolate) {
-        final boolean isRtl = heuristic.isRtl(str, 0, str.length());
-        String origStr = str;
-        str = TextUtils.htmlEncode(str);
-
-        StringBuilder result = new StringBuilder();
-        if (getStereoReset() && isolate) {
-            result.append(markBefore(origStr,
-                    isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
-        }
-        if (isRtl != mIsRtlContext) {
-            result.append("<span ").append(dirAttr(isRtl)).append('>').append(str).append("</span>");
-        } else {
-            result.append(str);
-        }
-        if (isolate) {
-            result.append(markAfter(origStr,
-                    isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR));
-        }
-        return result.toString();
-    }
-
-    /**
-     * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but assumes
-     * {@code isolate} is true.
-     *
-     * @param str The input string.
-     * @param heuristic The algorithm to be used to estimate the string's overall direction.
-     * @return Input string after applying the above processing.
-     */
-    public String spanWrap(String str, TextDirectionHeuristic heuristic) {
-        return spanWrap(str, heuristic, true /* isolate */);
-    }
-
-    /**
-     * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but uses the
-     * formatter's default direction estimation algorithm.
-     *
-     * @param str The input string.
-     * @param isolate Whether to directionally isolate the string to prevent it from garbling the
-     *     content around it
-     * @return Input string after applying the above processing.
-     */
-    public String spanWrap(String str, boolean isolate) {
-        return spanWrap(str, mDefaultTextDirectionHeuristic, isolate);
-    }
-
-    /**
-     * Operates like {@link #spanWrap(String, TextDirectionHeuristic, boolean)}, but uses the
-     * formatter's default direction estimation algorithm and assumes {@code isolate} is true.
-     *
-     * @param str The input string.
-     * @return Input string after applying the above processing.
-     */
-    public String spanWrap(String str) {
-        return spanWrap(str, mDefaultTextDirectionHeuristic, true /* isolate */);
-    }
-
-    /**
      * Formats a string of given directionality for use in plain-text output of the context
      * directionality, so an opposite-directionality string is neither garbled nor garbles its
-     * surroundings. As opposed to {@link #spanWrap}, this makes use of Unicode bidi
-     * formatting characters. In HTML, its *only* valid use is inside of elements that do not allow
-     * markup, e.g. the 'option' and 'title' elements.
+     * surroundings. This makes use of Unicode bidi formatting characters.
      * <p>
      * The algorithm: In case the given directionality doesn't match the context directionality, wraps
      * the string with Unicode bidi formatting characters: RLE+{@code str}+PDF for RTL text, or
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 2ab9bf8..e2035c2 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -44,6 +44,7 @@
 import android.text.style.TypefaceSpan;
 import android.text.style.URLSpan;
 import android.text.style.UnderlineSpan;
+import android.util.Log;
 import android.util.Printer;
 
 import android.view.View;
@@ -57,6 +58,8 @@
 import java.util.regex.Pattern;
 
 public class TextUtils {
+    private static final String TAG = "TextUtils";
+
 
     private TextUtils() { /* cannot be instantiated */ }
 
@@ -550,6 +553,8 @@
     /** @hide */
     public static final int ALIGNMENT_SPAN = 1;
     /** @hide */
+    public static final int FIRST_SPAN = ALIGNMENT_SPAN;
+    /** @hide */
     public static final int FOREGROUND_COLOR_SPAN = 2;
     /** @hide */
     public static final int RELATIVE_SIZE_SPAN = 3;
@@ -593,6 +598,8 @@
     public static final int EASY_EDIT_SPAN = 22;
     /** @hide */
     public static final int LOCALE_SPAN = 23;
+    /** @hide */
+    public static final int LAST_SPAN = LOCALE_SPAN;
 
     /**
      * Flatten a CharSequence and whatever styles can be copied across processes
@@ -622,9 +629,16 @@
 
                 if (prop instanceof ParcelableSpan) {
                     ParcelableSpan ps = (ParcelableSpan)prop;
-                    p.writeInt(ps.getSpanTypeId());
-                    ps.writeToParcel(p, parcelableFlags);
-                    writeWhere(p, sp, o);
+                    int spanTypeId = ps.getSpanTypeId();
+                    if (spanTypeId < FIRST_SPAN || spanTypeId > LAST_SPAN) {
+                        Log.e(TAG, "external class \"" + ps.getClass().getSimpleName()
+                                + "\" is attempting to use the frameworks-only ParcelableSpan"
+                                + " interface");
+                    } else {
+                        p.writeInt(spanTypeId);
+                        ps.writeToParcel(p, parcelableFlags);
+                        writeWhere(p, sp, o);
+                    }
                 }
             }
 
diff --git a/core/java/android/util/PropertyValueModel.java b/core/java/android/util/PropertyValueModel.java
deleted file mode 100755
index eb9c47d..0000000
--- a/core/java/android/util/PropertyValueModel.java
+++ /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.
- */
-
-package android.util;
-
-/**
- * A value model for a {@link Property property} of a host object. This class can be used for
- * both reflective and non-reflective property implementations.
- *
- * @param <H> the host type, where the host is the object that holds this property
- * @param <T> the value type
- *
- * @see Property
- * @see ValueModel
- */
-public class PropertyValueModel<H, T> extends ValueModel<T> {
-    private final H mHost;
-    private final Property<H, T> mProperty;
-
-    private PropertyValueModel(H host, Property<H, T> property) {
-        mProperty = property;
-        mHost = host;
-    }
-
-    /**
-     * Returns the host.
-     *
-     * @return the host
-     */
-    public H getHost() {
-        return mHost;
-    }
-
-    /**
-     * Returns the property.
-     *
-     * @return the property
-     */
-    public Property<H, T> getProperty() {
-        return mProperty;
-    }
-
-    @Override
-    public Class<T> getType() {
-        return mProperty.getType();
-    }
-
-    @Override
-    public T get() {
-        return mProperty.get(mHost);
-    }
-
-    @Override
-    public void set(T value) {
-        mProperty.set(mHost, value);
-    }
-
-    /**
-     * Return an appropriate PropertyValueModel for this host and property.
-     *
-     * @param host the host
-     * @param property the property
-     * @return the value model
-     */
-    public static <H, T> PropertyValueModel<H, T> of(H host, Property<H, T> property) {
-        return new PropertyValueModel<H, T>(host, property);
-    }
-
-    /**
-     * Return a PropertyValueModel for this {@code host} and a
-     * reflective property, constructed from this {@code propertyType} and {@code propertyName}.
-     *
-     * @param host
-     * @param propertyType the property type
-     * @param propertyName the property name
-     * @return a value model with this host and a reflective property with this type and name
-     *
-     * @see Property#of
-     */
-    public static <H, T> PropertyValueModel<H, T> of(H host, Class<T> propertyType,
-            String propertyName) {
-        return of(host, Property.of((Class<H>) host.getClass(), propertyType, propertyName));
-    }
-
-    private static Class getNullaryMethodReturnType(Class c, String name) {
-        try {
-            return c.getMethod(name).getReturnType();
-        } catch (NoSuchMethodException e) {
-            return null;
-        }
-    }
-
-    private static Class getFieldType(Class c, String name) {
-        try {
-            return c.getField(name).getType();
-        } catch (NoSuchFieldException e) {
-            return null;
-        }
-    }
-
-    private static String capitalize(String name) {
-        if (name.isEmpty()) {
-            return name;
-        }
-        return Character.toUpperCase(name.charAt(0)) + name.substring(1);
-    }
-
-    /**
-     * Return a PropertyValueModel for this {@code host} and and {@code propertyName}.
-     *
-     * @param host the host
-     * @param propertyName the property name
-     * @return a value model with this host and a reflective property with this name
-     */
-    public static PropertyValueModel of(Object host, String propertyName) {
-        Class clazz = host.getClass();
-        String suffix = capitalize(propertyName);
-        Class propertyType = getNullaryMethodReturnType(clazz, "get" + suffix);
-        if (propertyType == null) {
-            propertyType = getNullaryMethodReturnType(clazz, "is" + suffix);
-        } 
-        if (propertyType == null) {
-            propertyType = getFieldType(clazz, propertyName); 
-        }         
-        if (propertyType == null) {
-            throw new NoSuchPropertyException(propertyName); 
-        }
-        return of(host, propertyType, propertyName);
-    }
-}
diff --git a/core/java/android/util/ValueModel.java b/core/java/android/util/ValueModel.java
deleted file mode 100755
index 4789682..0000000
--- a/core/java/android/util/ValueModel.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 android.util;
-
-/**
- * A ValueModel is an abstraction for a 'slot' or place in memory in which a value
- * may be stored and retrieved. A common implementation of ValueModel is a regular property of
- * an object, whose value may be retrieved by calling the appropriate <em>getter</em>
- * method and set by calling the corresponding <em>setter</em> method.
- *
- * @param <T> the value type
- *
- * @see PropertyValueModel
- */
-public abstract class ValueModel<T> {
-    /**
-     * The empty model should be used in place of {@code null} to indicate that a
-     * model has not been set. The empty model has no value and does nothing when it is set.
-     */
-    public static final ValueModel EMPTY = new ValueModel() {
-        @Override
-        public Class getType() {
-            return Object.class;
-        }
-
-        @Override
-        public Object get() {
-            return null;
-        }
-
-        @Override
-        public void set(Object value) {
-
-        }
-    };
-
-    protected ValueModel() {
-    }
-
-    /**
-     * Returns the type of this property.
-     *
-     * @return the property type
-     */
-    public abstract Class<T> getType();
-
-    /**
-     * Returns the value of this property.
-     *
-     * @return the property value
-     */
-    public abstract T get();
-
-    /**
-     * Sets the value of this property.
-     *
-     * @param value the new value for this property
-     */
-    public abstract void set(T value);
-}
\ No newline at end of file
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index edfef56..4989c3a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -220,14 +220,14 @@
     /**
      * Gets a {@link Canvas} for drawing into this surface.
      *
-     * After drawing into the provided {@link Canvas}, the caller should
+     * After drawing into the provided {@link Canvas}, the caller must
      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
      *
      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
      * to redraw.  This function may choose to expand the dirty rectangle if for example
      * the surface has been resized or if the previous contents of the surface were
-     * not available.  The caller should redraw the entire dirty region as represented
-     * by the contents of the dirty rect upon return from this function.
+     * not available.  The caller must redraw the entire dirty region as represented
+     * by the contents of the inOutDirty rectangle upon return from this function.
      * The caller may also pass <code>null</code> instead, in the case where the
      * entire surface should be redrawn.
      * @return A canvas for drawing into the surface.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 14fa9cb..793fb5e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -755,12 +755,36 @@
             mHandler.sendMessage(msg);
         }
         
+        /**
+         * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+         *
+         * After drawing into the provided {@link Canvas}, the caller must
+         * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+         *
+         * The caller must redraw the entire surface.
+         * @return A canvas for drawing into the surface.
+         */
         public Canvas lockCanvas() {
             return internalLockCanvas(null);
         }
 
-        public Canvas lockCanvas(Rect dirty) {
-            return internalLockCanvas(dirty);
+        /**
+         * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
+         *
+         * After drawing into the provided {@link Canvas}, the caller must
+         * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+         *
+         * @param inOutDirty A rectangle that represents the dirty region that the caller wants
+         * to redraw.  This function may choose to expand the dirty rectangle if for example
+         * the surface has been resized or if the previous contents of the surface were
+         * not available.  The caller must redraw the entire dirty region as represented
+         * by the contents of the inOutDirty rectangle upon return from this function.
+         * The caller may also pass <code>null</code> instead, in the case where the
+         * entire surface should be redrawn.
+         * @return A canvas for drawing into the surface.
+         */
+        public Canvas lockCanvas(Rect inOutDirty) {
+            return internalLockCanvas(inOutDirty);
         }
 
         private final Canvas internalLockCanvas(Rect dirty) {
@@ -810,6 +834,12 @@
             return null;
         }
 
+        /**
+         * Posts the new contents of the {@link Canvas} to the surface and
+         * releases the {@link Canvas}.
+         *
+         * @param canvas The canvas previously obtained from {@link #lockCanvas}.
+         */
         public void unlockCanvasAndPost(Canvas canvas) {
             mSurface.unlockCanvasAndPost(canvas);
             mSurfaceLock.unlock();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4fb2431..a0a63a6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2915,14 +2915,14 @@
      *
      * @hide
      */
-    int mUserPaddingLeftInitial = 0;
+    int mUserPaddingLeftInitial;
 
     /**
      * Cache initial right padding.
      *
      * @hide
      */
-    int mUserPaddingRightInitial = 0;
+    int mUserPaddingRightInitial;
 
     /**
      * Default undefined padding
@@ -3388,11 +3388,11 @@
                     break;
                 case com.android.internal.R.styleable.View_paddingStart:
                     startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING);
-                    startPaddingDefined = true;
+                    startPaddingDefined = (startPadding != UNDEFINED_PADDING);
                     break;
                 case com.android.internal.R.styleable.View_paddingEnd:
                     endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING);
-                    endPaddingDefined = true;
+                    endPaddingDefined = (endPadding != UNDEFINED_PADDING);
                     break;
                 case com.android.internal.R.styleable.View_scrollX:
                     x = a.getDimensionPixelOffset(attr, 0);
@@ -3712,10 +3712,12 @@
             // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial
             // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if
             // defined.
-            if (leftPaddingDefined) {
+            final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined;
+
+            if (leftPaddingDefined && !hasRelativePadding) {
                 mUserPaddingLeftInitial = leftPadding;
             }
-            if (rightPaddingDefined) {
+            if (rightPaddingDefined && !hasRelativePadding) {
                 mUserPaddingRightInitial = rightPadding;
             }
         }
@@ -11952,26 +11954,30 @@
             // left / right or right / left depending on the resolved layout direction.
             // If start / end padding are not defined, use the left / right ones.
             int resolvedLayoutDirection = getLayoutDirection();
-            // Set user padding to initial values ...
-            mUserPaddingLeft = mUserPaddingLeftInitial;
-            mUserPaddingRight = mUserPaddingRightInitial;
-            // ... then resolve it.
             switch (resolvedLayoutDirection) {
                 case LAYOUT_DIRECTION_RTL:
                     if (mUserPaddingStart != UNDEFINED_PADDING) {
                         mUserPaddingRight = mUserPaddingStart;
+                    } else {
+                        mUserPaddingRight = mUserPaddingRightInitial;
                     }
                     if (mUserPaddingEnd != UNDEFINED_PADDING) {
                         mUserPaddingLeft = mUserPaddingEnd;
+                    } else {
+                        mUserPaddingLeft = mUserPaddingLeftInitial;
                     }
                     break;
                 case LAYOUT_DIRECTION_LTR:
                 default:
                     if (mUserPaddingStart != UNDEFINED_PADDING) {
                         mUserPaddingLeft = mUserPaddingStart;
+                    } else {
+                        mUserPaddingLeft = mUserPaddingLeftInitial;
                     }
                     if (mUserPaddingEnd != UNDEFINED_PADDING) {
                         mUserPaddingRight = mUserPaddingEnd;
+                    } else {
+                        mUserPaddingRight = mUserPaddingRightInitial;
                     }
             }
 
@@ -13380,18 +13386,32 @@
 
     /**
      * Sets a rectangular area on this view to which the view will be clipped
-     * it is drawn. Setting the value to null will remove the clip bounds
+     * when it is drawn. Setting the value to null will remove the clip bounds
      * and the view will draw normally, using its full bounds.
      *
      * @param clipBounds The rectangular area, in the local coordinates of
      * this view, to which future drawing operations will be clipped.
      */
     public void setClipBounds(Rect clipBounds) {
-        mClipBounds = clipBounds;
         if (clipBounds != null) {
-            invalidate(clipBounds);
+            if (clipBounds.equals(mClipBounds)) {
+                return;
+            }
+            if (mClipBounds == null) {
+                invalidate();
+                mClipBounds = new Rect(clipBounds);
+            } else {
+                invalidate(Math.min(mClipBounds.left, clipBounds.left),
+                        Math.min(mClipBounds.top, clipBounds.top),
+                        Math.max(mClipBounds.right, clipBounds.right),
+                        Math.max(mClipBounds.bottom, clipBounds.bottom));
+                mClipBounds.set(clipBounds);
+            }
         } else {
-            invalidate();
+            if (mClipBounds != null) {
+                invalidate();
+                mClipBounds = null;
+            }
         }
     }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 98df064..528eadd 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.animation.Animatable;
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.animation.TimeInterpolator;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 48630a4..d52b1f3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -795,9 +795,7 @@
          * <p>This flag can be controlled in your theme through the
          * {@link android.R.attr#windowOverscan} attribute; this attribute
          * is automatically set for you in the standard overscan themes
-         * such as {@link android.R.style#Theme_NoTitleBar_Overscan},
-         * {@link android.R.style#Theme_Black_NoTitleBar_Overscan},
-         * {@link android.R.style#Theme_Light_NoTitleBar_Overscan},
+         * such as
          * {@link android.R.style#Theme_Holo_NoActionBar_Overscan},
          * {@link android.R.style#Theme_Holo_Light_NoActionBar_Overscan},
          * {@link android.R.style#Theme_DeviceDefault_NoActionBar_Overscan}, and
@@ -1276,10 +1274,11 @@
         public static final int ROTATION_ANIMATION_JUMPCUT = 2;
 
         /**
-         * Define the animation used on this window for entry or exit following
-         * a rotation. This only works if the incoming and outgoing topmost
+         * Define the exit and entry animations used on this window when the device is rotated.
+         * This only has an affect if the incoming and outgoing topmost
          * opaque windows have the #FLAG_FULLSCREEN bit set and are not covered
-         * by other windows.
+         * by other windows. All other situations default to the
+         * {@link #ROTATION_ANIMATION_ROTATE} behavior.
          * 
          * @see #ROTATION_ANIMATION_ROTATE
          * @see #ROTATION_ANIMATION_CROSSFADE
@@ -1364,7 +1363,7 @@
         /**
          * Control special features of the input subsystem.
          *
-         * @see #INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES
+         * @see #INPUT_FEATURE_DISABLE_POINTER_GESTURES
          * @see #INPUT_FEATURE_NO_INPUT_CHANNEL
          * @see #INPUT_FEATURE_DISABLE_USER_ACTIVITY
          * @hide
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index c7dacf3..a324502 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -2149,7 +2149,8 @@
     @Override
     public void destroy() {
         if (mWebView.getViewRootImpl() != null) {
-            Log.e(LOGTAG, "Error: WebView.destroy() called while still attached!");
+            Log.e(LOGTAG, Log.getStackTraceString(
+                    new Throwable("Error: WebView.destroy() called while still attached!")));
         }
         ensureFunctorDetached();
         destroyJava();
diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java
index 41ab5f2..f1804f8 100644
--- a/core/java/android/widget/CheckBox.java
+++ b/core/java/android/widget/CheckBox.java
@@ -20,7 +20,6 @@
 import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.util.ValueModel;
 
 
 /**
@@ -56,9 +55,7 @@
  * {@link android.R.styleable#View View Attributes}
  * </p>
  */
-public class CheckBox extends CompoundButton implements ValueEditor<Boolean> {
-    private ValueModel<Boolean> mValueModel = ValueModel.EMPTY;
-
+public class CheckBox extends CompoundButton {
     public CheckBox(Context context) {
         this(context, null);
     }
@@ -82,22 +79,4 @@
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(CheckBox.class.getName());
     }
-
-    @Override
-    public ValueModel<Boolean> getValueModel() {
-        return mValueModel;
-    }
-
-    @Override
-    public void setValueModel(ValueModel<Boolean> valueModel) {
-        mValueModel = valueModel;
-        setChecked(mValueModel.get());
-    }
-
-    @Override
-    public boolean performClick() {
-        boolean handled = super.performClick();
-        mValueModel.set(isChecked());
-        return handled;
-    }
 }
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index ec81214..57e51c2 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,7 +17,6 @@
 package android.widget;
 
 import android.content.Context;
-import android.graphics.Rect;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
@@ -25,7 +24,6 @@
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
-import android.util.ValueModel;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
@@ -49,9 +47,7 @@
  * {@link android.R.styleable#TextView TextView Attributes},
  * {@link android.R.styleable#View View Attributes}
  */
-public class EditText extends TextView implements ValueEditor<CharSequence> {
-    private ValueModel<CharSequence> mValueModel = ValueModel.EMPTY;
-
+public class EditText extends TextView {
     public EditText(Context context) {
         this(context, null);
     }
@@ -132,21 +128,4 @@
         super.onInitializeAccessibilityNodeInfo(info);
         info.setClassName(EditText.class.getName());
     }
-
-    @Override
-    public ValueModel<CharSequence> getValueModel() {
-        return mValueModel;
-    }
-
-    @Override
-    public void setValueModel(ValueModel<CharSequence> valueModel) {
-        mValueModel = valueModel;
-        setText(mValueModel.get());
-    }
-
-    @Override
-    void sendAfterTextChanged(Editable text) {
-        super.sendAfterTextChanged(text);
-        mValueModel.set(text);
-    }
 }
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 85ed8db..2309001 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -944,15 +944,17 @@
 
     // Measurement
 
+    // Note: padding has already been removed from the supplied specs
     private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
             int childWidth, int childHeight) {
         int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
-                mPaddingLeft + mPaddingRight + getTotalMargin(child, true), childWidth);
+                getTotalMargin(child, true), childWidth);
         int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
-                mPaddingTop + mPaddingBottom + getTotalMargin(child, false), childHeight);
+                getTotalMargin(child, false), childHeight);
         child.measure(childWidthSpec, childHeightSpec);
     }
 
+    // Note: padding has already been removed from the supplied specs
     private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
@@ -979,6 +981,11 @@
         }
     }
 
+    static int adjust(int measureSpec, int delta) {
+        return makeMeasureSpec(
+                MeasureSpec.getSize(measureSpec + delta),  MeasureSpec.getMode(measureSpec));
+    }
+
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
         consistencyCheck();
@@ -987,29 +994,33 @@
          *  is  likely to have changed. We must invalidate if so. */
         invalidateValues();
 
-        measureChildrenWithMargins(widthSpec, heightSpec, true);
+        int hPadding = getPaddingLeft() + getPaddingRight();
+        int vPadding = getPaddingTop()  + getPaddingBottom();
 
-        int width, height;
+        int widthSpecSansPadding =  adjust( widthSpec, -hPadding);
+        int heightSpecSansPadding = adjust(heightSpec, -vPadding);
+
+        measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, true);
+
+        int widthSansPadding;
+        int heightSansPadding;
 
         // Use the orientation property to decide which axis should be laid out first.
         if (orientation == HORIZONTAL) {
-            width = horizontalAxis.getMeasure(widthSpec);
-            measureChildrenWithMargins(widthSpec, heightSpec, false);
-            height = verticalAxis.getMeasure(heightSpec);
+            widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
+            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
+            heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
         } else {
-            height = verticalAxis.getMeasure(heightSpec);
-            measureChildrenWithMargins(widthSpec, heightSpec, false);
-            width = horizontalAxis.getMeasure(widthSpec);
+            heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
+            measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
+            widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
         }
 
-        int hPadding = getPaddingLeft() + getPaddingRight();
-        int vPadding = getPaddingTop() + getPaddingBottom();
-
-        int measuredWidth = Math.max(hPadding + width, getSuggestedMinimumWidth());
-        int measuredHeight = Math.max(vPadding + height, getSuggestedMinimumHeight());
+        int measuredWidth  = Math.max(widthSansPadding  + hPadding, getSuggestedMinimumWidth());
+        int measuredHeight = Math.max(heightSansPadding + vPadding, getSuggestedMinimumHeight());
 
         setMeasuredDimension(
-                resolveSizeAndState(measuredWidth, widthSpec, 0),
+                resolveSizeAndState(measuredWidth,   widthSpec, 0),
                 resolveSizeAndState(measuredHeight, heightSpec, 0));
     }
 
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c7914f3..f42999d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -41,6 +41,7 @@
 import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
 import android.widget.RemoteViews.RemoteView;
 
 import java.util.ArrayList;
@@ -1715,11 +1716,17 @@
             }
 
             // Attempt to restore accessibility focus.
-            if (accessibilityFocusLayoutRestoreNode != null) {
-                accessibilityFocusLayoutRestoreNode.performAction(
-                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
-            } else if (accessibilityFocusLayoutRestoreView != null) {
-                accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+            if (accessibilityFocusLayoutRestoreView != null) {
+                final AccessibilityNodeProvider provider =
+                        accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
+                if ((accessibilityFocusLayoutRestoreNode != null) && (provider != null)) {
+                    final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
+                            accessibilityFocusLayoutRestoreNode.getSourceNodeId());
+                    provider.performAction(virtualViewId,
+                            AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+                } else {
+                    accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+                }
             } else if (accessibilityFocusPosition != INVALID_POSITION) {
                 // Bound the position within the visible children.
                 final int position = MathUtils.constrain(
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 83e2e79e..07e66b7 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2108,6 +2108,8 @@
      *      RemoteViews. This count cannot change during the life-cycle of a given widget, so this
      *      parameter should account for the maximum possible number of types that may appear in the
      *      See {@link Adapter#getViewTypeCount()}.
+     *
+     * @hide
      */
     public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
         addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index a6486a8..2737f94 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.ValueModel;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 
@@ -34,7 +33,7 @@
  *
  * @attr ref android.R.styleable#SeekBar_thumb
  */
-public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> {
+public class SeekBar extends AbsSeekBar {
 
     /**
      * A callback that notifies clients when the progress level has been
@@ -70,9 +69,8 @@
         void onStopTrackingTouch(SeekBar seekBar);
     }
 
-    private ValueModel<Integer> mValueModel = ValueModel.EMPTY;
     private OnSeekBarChangeListener mOnSeekBarChangeListener;
-
+    
     public SeekBar(Context context) {
         this(context, null);
     }
@@ -91,23 +89,9 @@
 
         if (mOnSeekBarChangeListener != null) {
             mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
-            if (fromUser) {
-                mValueModel.set(getProgress());
-            }
         }
     }
 
-    @Override
-    public ValueModel<Integer> getValueModel() {
-        return mValueModel;
-    }
-
-    @Override
-    public void setValueModel(ValueModel<Integer> valueModel) {
-        mValueModel = valueModel;
-        setProgress(mValueModel.get());
-    }
-
     /**
      * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also
      * provides notifications of when the user starts and stops a touch gesture within the SeekBar.
diff --git a/core/java/android/widget/ValueEditor.java b/core/java/android/widget/ValueEditor.java
deleted file mode 100755
index 2b91abf..0000000
--- a/core/java/android/widget/ValueEditor.java
+++ /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.
- */
-
-package android.widget;
-
-import android.util.ValueModel;
-
-/**
- * An interface for editors of simple values. Classes implementing this interface are normally
- * UI controls (subclasses of {@link android.view.View View}) that can provide a suitable
- * user interface to display and edit values of the specified type. This interface is
- * intended to describe editors for simple types, like {@code boolean}, {@code int} or
- * {@code String}, where the values themselves are immutable.
- * <p>
- * For example, {@link android.widget.CheckBox CheckBox} implements
- * this interface for the Boolean type as it is capable of providing an appropriate
- * mechanism for displaying and changing the value of a Boolean property.
- *
- * @param <T> the value type that this editor supports
- */
-public interface ValueEditor<T> {
-    /**
-     * Return the last value model that was set. If no value model has been set, the editor
-     * should return the value {@link android.util.ValueModel#EMPTY}.
-     *
-     * @return the value model
-     */
-    public ValueModel<T> getValueModel();
-
-    /**
-     * Sets the value model for this editor. When the value model is set, the editor should
-     * retrieve the value from the value model, using {@link android.util.ValueModel#get()},
-     * and set its internal state accordingly. Likewise, when the editor's internal state changes
-     * it should update the value model by calling  {@link android.util.ValueModel#set(T)}
-     * with the appropriate value.
-     *
-     * @param valueModel the new value model for this editor.
-     */
-    public void setValueModel(ValueModel<T> valueModel);
-}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 7eddc9c..2184fd2 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -25,6 +25,7 @@
 import android.os.Debug;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.util.EventLog;
 import android.util.Log;
 
@@ -528,6 +529,10 @@
             // Do an initial gc to clean up after startup
             gc();
 
+            // Disable tracing so that forked processes do not inherit stale tracing tags from
+            // Zygote.
+            Trace.setTracingEnabled(false);
+
             // If requested, start system server directly from Zygote
             if (argv.length != 2) {
                 throw new RuntimeException(argv[0] + USAGE_STRING);
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 59ff597..d69bc31 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1354,7 +1354,7 @@
 
     public void setHomeActionContentDescription(int resId) {
         mHomeDescriptionRes = resId;
-        mHomeDescription = getResources().getText(resId);
+        mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
     }
 
     static class SavedState extends BaseSavedState {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 555c7c2..d3ead26 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -140,6 +140,10 @@
 
     public final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
 
+    private static final String LOCK_SCREEN_OWNER_INFO = Settings.Secure.LOCK_SCREEN_OWNER_INFO;
+    private static final String LOCK_SCREEN_OWNER_INFO_ENABLED =
+            Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
+
     private final Context mContext;
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
@@ -526,6 +530,22 @@
         }
     }
 
+    public void setOwnerInfo(String info, int userId) {
+        setString(LOCK_SCREEN_OWNER_INFO, info, userId);
+    }
+
+    public void setOwnerInfoEnabled(boolean enabled) {
+        setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled);
+    }
+
+    public String getOwnerInfo(int userId) {
+        return getString(LOCK_SCREEN_OWNER_INFO);
+    }
+
+    public boolean isOwnerInfoEnabled() {
+        return getBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, false);
+    }
+
     /**
      * Compute the password quality from the given password string.
      */
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 1ace23e..17f205d 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -339,23 +339,11 @@
 }
 
 TextLayoutShaper::TextLayoutShaper() {
-    init();
-
     mBuffer = hb_buffer_create();
 }
 
-void TextLayoutShaper::init() {
-    mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
-}
-
-void TextLayoutShaper::unrefTypefaces() {
-    SkSafeUnref(mDefaultTypeface);
-}
-
 TextLayoutShaper::~TextLayoutShaper() {
     hb_buffer_destroy(mBuffer);
-
-    unrefTypefaces();
 }
 
 void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
@@ -839,23 +827,27 @@
     }
 
     if (baseGlyphCount != 0) {
+        SkTypeface::Style style = SkTypeface::kNormal;
+        if (typeface != NULL) {
+            style = typeface->style();
+        }
         typeface = typefaceForScript(paint, typeface, hb_buffer_get_script(mBuffer));
         if (!typeface) {
             baseGlyphCount = 0;
-            typeface = mDefaultTypeface;
-            SkSafeRef(typeface);
+            typeface = SkFontHost::CreateTypeface(NULL, NULL, style);
 #if DEBUG_GLYPHS
             ALOGD("Using Default Typeface");
 #endif
         }
     } else {
         if (!typeface) {
-            typeface = mDefaultTypeface;
+            typeface = SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
 #if DEBUG_GLYPHS
-            ALOGD("Using Default Typeface");
+            ALOGD("Using Default Typeface (normal style)");
 #endif
+        } else {
+            SkSafeRef(typeface);
         }
-        SkSafeRef(typeface);
     }
 
     mShapingPaint.setTypeface(typeface);
@@ -899,8 +891,6 @@
         hb_face_destroy(mCachedHBFaces.valueAt(i));
     }
     mCachedHBFaces.clear();
-    unrefTypefaces();
-    init();
 }
 
 TextLayoutEngine::TextLayoutEngine() {
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index f9b9900..5414a11 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -197,18 +197,10 @@
     SkPaint mShapingPaint;
 
     /**
-     * Skia default typeface to be returned if we cannot resolve script
-     */
-    SkTypeface* mDefaultTypeface;
-
-    /**
      * Cache of Harfbuzz faces
      */
     KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
 
-    void init();
-    void unrefTypefaces();
-
     SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
         hb_script_t script);
 
@@ -228,7 +220,6 @@
     hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
 
     bool isComplexScript(hb_script_t script);
-
 }; // TextLayoutShaper
 
 /**
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 1315291..01d02c5 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -86,6 +86,11 @@
     atrace_set_debuggable(allowed);
 }
 
+static void android_os_Trace_nativeSetTracingEnabled(JNIEnv* env,
+        jclass clazz, jboolean enabled) {
+    atrace_set_tracing_enabled(enabled);
+}
+
 static JNINativeMethod gTraceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeGetEnabledTags",
@@ -109,6 +114,9 @@
     { "nativeSetAppTracingAllowed",
             "(Z)V",
             (void*)android_os_Trace_nativeSetAppTracingAllowed },
+    { "nativeSetTracingEnabled",
+            "(Z)V",
+            (void*)android_os_Trace_nativeSetTracingEnabled },
 };
 
 int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6b4fe79..cb14374 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -134,6 +134,7 @@
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" />
     <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" />
     <protected-broadcast android:name="android.net.conn.DATA_ACTIVITY_CHANGE" />
+    <protected-broadcast android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED" />
     <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED" />
 
     <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
@@ -544,6 +545,7 @@
     <!-- =============================================== -->
     <!-- Permissions for enabling accessibility features -->
     <!-- =============================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that allow requesting certain accessibility features. -->
     <permission-group android:name="android.permission-group.ACCESSIBILITY_FEATURES"
@@ -552,20 +554,6 @@
         android:description="@string/permgroupdesc_accessibilityFeatures"
         android:priority="380" />
 
-    <!-- Allows an accessibility service to request touch exploration mode. -->
-    <permission android:name="android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE"
-        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
-        android:label="@string/permlab_canRequestTouchExplorationMode"
-        android:description="@string/permdesc_canRequestTouchExplorationMode"
-        android:protectionLevel="dangerous" />
-
-    <!-- Allows an accessibility service to request enhanced web accessibility. -->
-    <permission android:name="android.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"
-        android:permissionGroup="android.permission-group.ACCESSIBILITY_FEATURES"
-        android:label="@string/permlab_canRequestEnahncedWebAccessibility"
-        android:description="@string/permdesc_canRequestEnahncedWebAccessibility"
-        android:protectionLevel="dangerous" />
-
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
@@ -836,6 +824,7 @@
     <!-- ==================================================== -->
     <!-- Permissions related to changing audio settings   -->
     <!-- ==================================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that provide direct access to speaker settings
          the device. -->
@@ -918,7 +907,8 @@
     <permission android:name="android.permission.RECORD_AUDIO"
         android:permissionGroup="android.permission-group.MICROPHONE"
         android:protectionLevel="dangerous"
-        android:label="@string/permlab_recordAudio" />
+        android:label="@string/permlab_recordAudio"
+        android:description="@string/permdesc_recordAudio" />
 
 
     <!-- =========================================== -->
@@ -1274,6 +1264,7 @@
     <!-- ==================================================== -->
     <!-- Permissions related to changing status bar   -->
     <!-- ==================================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that change the status bar -->
     <permission-group android:name="android.permission-group.STATUS_BAR"
@@ -1292,6 +1283,7 @@
     <!-- ==================================================== -->
     <!-- Permissions related to accessing sync settings   -->
     <!-- ==================================================== -->
+    <eat-comment />
 
     <!-- Used for permissions that access the sync settings or sync
          related information. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index ea194fc..f1119e2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Herlaai"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Die bladsy by \"<xliff:g id="TITLE">%s</xliff:g>\" sê:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigeer weg van hierdie bladsy?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Raak OK om voort te gaan, of Kanselleer om op die huidige bladsy te bly."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bevestig"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Wenk: Dubbeltik om in en uit te zoem."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Outovul"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 84eba57..d689022 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -387,7 +387,7 @@
     <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"በሌሎች መተግበሪያዎች የመሸጎጫ ማውጫዎች ውስጥ ያሉትን ፋይሎች በመሰረዝ መተግበሪያው የጡባዊ ማከማቻ ቦታ ነጻ እንዲያስለቅቅ ያስችለዋል። ይሄ ሌሎች መተግበሪያዎች ውሂባቸውን ዳግም ማምጣት ስላለባቸው ይበልጥ ዘግየት ብለው እንዲጀምሩ ሊያደርጋቸው ይችላል።"</string>
     <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"በሌሎች መተግበሪያዎች የመሸጎጫ ማውጫዎች ውስጥ ያሉትን ፋይሎች በመሰረዝ መተግበሪያው የስልክ ማከማቻ ቦታ ነጻ እንዲያስለቅቅ ያስችለዋል። ይሄ ሌሎች መተግበሪያዎች ውሂባቸውን ዳግም ማምጣት ስላለባቸው ይበልጥ ዘግየት ብለው እንዲጀምሩ ሊያደርጋቸው ይችላል።"</string>
     <string name="permlab_movePackage" msgid="3289890271645921411">"የመተግበሪያ ሃብቶችን አንቀሳቅስ"</string>
-    <string name="permdesc_movePackage" msgid="319562217778244524">"ከውስጣዊ ወደ  ውጫዊ ሚዲያ እና በተገላቢጦሽ የመተግበሪያ ሃብቶችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
+    <string name="permdesc_movePackage" msgid="319562217778244524">"ከውስጣዊ ወደ  ውጫዊ ማህደረ  መረጃ  እና በተገላቢጦሽ የመተግበሪያ ሃብቶችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_readLogs" msgid="6615778543198967614">"ወሳኝ የማስታወሻ ውሂብ አንብብ"</string>
     <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">" ከስርዓቱ የተለያዩ የማስታወሻ ፋይሎች ውስጥ ለማንበብ ለመተግበሪያ ይፈቅዳሉ። ይህ ስለ ጡባዊ ተኮህ ምን እያደረክበት እንደሆነ የግላዊ  ወይም የግል መረጃን ጨምሮ ጠቅላላ መረጃ ለማግኘት ይፈቅዳል።"</string>
     <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">" ከስርዓቱ የተለያዩ የማስታወሻ ፋይሎች ውስጥ ለማንበብ ለመተግበሪያይፈቅዳሉ። ይህ ስለ ስልክህ ምን እያደረክበት እንደሆነ የግላዊ  ወይም የግል መረጃን ጨምሮ ጠቅላላ መረጃ ለማግኘት ይፈቅዳል።"</string>
@@ -403,9 +403,9 @@
     <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"ተመራጭ መተግበሪያዎች አዘጋጅ"</string>
     <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"ተመራጭ መተግበሪያዎችህን ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ ከአንተ የግል ውሂብ ለመሰብሰብ ያሉትን መተግበሪያዎች በመላክ፤ በመሄድ ላይ ያሉ መተግበሪያዎችን  ተንኮል አዘል መተግበሪያዎች በዝምታ ሊለውጡ ይችላሉ፡፡"</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"የስርዓት ቅንብሮችን አስተካክል"</string>
-    <string name="permdesc_writeSettings" msgid="7775723441558907181">"የስርዓት ቅንጅቶችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች የስርዓትህን አወቃቀር ብልሹ ሊያደርጉት ይችላሉ፡፡"</string>
+    <string name="permdesc_writeSettings" msgid="7775723441558907181">"የስርዓት ቅንብሮችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ። ተንኮል አዘል መተግበሪያዎች የስርዓትዎን አወቃቀር ብልሹ ሊያደርጉት ይችላሉ።"</string>
     <string name="permlab_writeSecureSettings" msgid="204676251876718288">"የስርዓት ቅንብሮችንደህንነት ቀይር"</string>
-    <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"የስርዓቱን ደህንነቱ የተጠበቀ ቅንጅቶችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡ለመደበኛ ትግበራዎች  አያስፈልግም።"</string>
+    <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"የስርዓቱን ደህንነቱ የተጠበቀ ቅንብሮችን ውሂብ ለመቀየር ለመተግበሪያው ይፈቅዳሉ። ለመደበኛ ትግበራዎች አያስፈልግም።"</string>
     <string name="permlab_writeGservices" msgid="2149426664226152185">"የGoogle አገልግሎቶች ካርታን ቀይር"</string>
     <string name="permdesc_writeGservices" msgid="1287309437638380229">"ትግበራ የGoogle ካርታ አገልግሎቶችን ለመቀየር ይፈቅዳል።ለመደበኛ ትግበራዎች ጥቅም አይደለም።"</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"መነሻ ላይ አሂድ"</string>
@@ -541,8 +541,8 @@
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"እንደ አውርድአዸራጅአገልግሎት"</string>
     <string name="permdesc_accountManagerService" msgid="1948455552333615954">" ወደ መለያ አረጋጋጮች ጥሪ ለማድረግ ለመተግበሪያ ይፈቅዳሉ።"</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን አግኝ"</string>
-    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንካቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
-    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንካቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
+    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
     <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"መለያዎችን ፍጠርና የይለፍ ቃላትን አስቀምጥ"</string>
     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"የመለያ አረጋጋጭ መለያ መናጅ ችሎታን ለመጠቀም፣ መለያ መፍጠር እና የይለፍ ቃሎችን ለማግኘት እና ለማቀናጀት አክሎ ለመተግበሪያው ይፈቅዳሉ ።"</string>
     <string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን አክል ወይም አስወግድ"</string>
@@ -554,7 +554,7 @@
     <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ሙሉ የአውታረ መረብ መዳረሻ"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"መተግበሪያው የአውታረ መረብ መሰኪያዎችን እንዲፈጥር እና ብጁ የአውታረ መረብ ፕሮቶኮሎችን እንዲጠቀም ይፈቅድለታል። አሳሹ እና ሌሎች መተግበሪያዎች ውሂብ ወደ በይነመረብ የመላኪያ መንገዶችን ስለሚያቀርቡውሂብ ወደ በይነመረብ ለመላክ ይህ ፍቃድ አያስፈልግም።"</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"የአውታረ መረብ ቅንብሮች እና ትራፊክ ለውጥ/ አቋርጥ"</string>
-    <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"የአውታረ መረብ ቅንጅቶችን ለመለወጥ እና ለማቋረጥ እና ሁሉንም የአውታረ መረብ ትራፊክ ለመመርመር፤ለምሳሌ ወኪል እና የማንኛውም APN ወደብ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ተንኮል አዘል መተግበሪያዎች ሊቆጣጠሩ፣ አቅጣጫ ሊያስቀይሩ ፣ ወይም ያለአንተ እውቅና የአውታረ መረብ ፓኬቶችን ሊቀይሩ ይችላሉ፡፡"</string>
+    <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"የአውታረ መረብ ቅንብሮችን ለመለወጥ እና ለማቋረጥ እና ሁሉንም የአውታረ መረብ ትራፊክ ለመመርመር፤ለምሳሌ ወኪል እና የማንኛውም APN ወደብ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ። ተንኮል አዘል መተግበሪያዎች ሊቆጣጠሩ፣ አቅጣጫ ሊያስቀይሩ ፣ ወይም ያለእርስዎ እውቅና የአውታረ መረብ ፓኬቶችን ሊቀይሩ ይችላሉ።"</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"የአውታረ መረብ ተያያዥነትን ለውጥ"</string>
     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"የእውታረ መረቡን ግንኙነት  ሁኔታ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_changeTetherState" msgid="5952584964373017960">"የተያያዘ ግንኙነት ለውጥ"</string>
@@ -601,7 +601,7 @@
     <string name="permlab_sdcardRead" product="default" msgid="8235341515605559677">"ጥበቃ ወደሚደረግለት ማከማቻ ያለ መዳረሻን ፈትሽ"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3642473292348132072">"መተግበሪያው በወደፊት መሳሪዎች ላይ ለሚኖር የUSB ማህደረ ትውስታ ፈቃድ እንዲሞክር ይፈቅድለታል።"</string>
     <string name="permdesc_sdcardRead" product="default" msgid="5914402684685848828">"መተግበሪያው በወደፊት መሳሪዎች ላይ ለሚኖረው SD ካርድ ፈቃድ እንዲሞክር ይፈቅድለታል።"</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"የUSB ማከማቻህን ይዘቶች ቀይር ወይም ሰርዝ"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"የUSB ማከማቻዎን ይዘቶች ይቀይሩ ወይም ይሰርዙ"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"የSD ካርድህን ይዘቶች ቀይር ወይም ሰርዝ"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"ወደ USB ማህደረ ትውስታው ለመፃፍ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"መተግበሪያውን ወደ SD ካርድ ለመፃፍ ይፈቅዳል።"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"ድጋሚ አስነሳ"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"በ«<xliff:g id="TITLE">%s</xliff:g>» ያለው ገጽ ይህን ይላል፦"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"ጃቫስክሪፕት"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"ከዚህ ገፅ ወጣ ብሎ ይዳስ? "\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" ለመቀጠል እሺ ፣ወይም የአሁኑ ገፅ ላይ ለመቆየት ይቅር ምረጥ።"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"አረጋግጥ"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"ጠቃሚ ምክር፦ ለማጉላት እና ለማሳነስ ሁለቴ-መታ አድርግ።"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ራስ ሙላ"</string>
@@ -1174,20 +1181,20 @@
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"አዲስ፦ "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የቀረበ።"</string>
     <string name="no_permissions" msgid="7283357728219338112">"ምንም ፍቃዶች አይጠየቁም"</string>
-    <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎብዎት ይችላል"</string>
+    <string name="perm_costs_money" msgid="4902470324142151116">"ይህ ገንዘብ ሊያስወጣዎት ይችላል"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB ብዙ ማከማቻ"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB ተያይዟል"</string>
     <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"ከኮምፒዩተርህ ጋር በUSB በኩል አገናኝተሃል። በኮምፒዩተርህ እና በAndroid SD ማከማቻህ መካከል ፋይሎች ለመቅዳት ከፈለግህ ከዚህ በታች ያለውን አዝራር ንካ።"</string>
     <string name="usb_storage_message" product="default" msgid="805351000446037811">"ከኮምፒዩተርህ ጋር በUSB በኩል አገናኝተሃል። በኮምፒዩተርህ እና በAndroid SD ማከማቻህ መካከል ፋይሎች ለመቅዳት ከፈለግህ ከዚህ በታች ያለውን አዝራር ንካ።"</string>
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"የUSB ማከማቻ አብራ"</string>
-    <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"የUSB ማከማቻህን ለUSB ብዙማከማቻ መጠቀም ችግር አለ።"</string>
+    <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"የUSB ማከማቻዎን ለUSB ብዙ ማከማቻ መጠቀም ችግር አለ።"</string>
     <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"የ SD ካርድህን ለUSB ብዙማከማቻ መጠቀም ችግር አለ።"</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB ተያይዟል"</string>
     <string name="usb_storage_notification_message" msgid="939822783828183763">"ፋይሎችን ከ/ወደ ኮምፒዩተርህ ለመቅዳት ንካ።"</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"የUSB ማከማቻ አጥፋ"</string>
     <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"የUSB ማከማቻ ለማጥፋት ንካ።"</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB ማከማቻ በጥቅም ላይ"</string>
-    <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"USB ማከማቻን ከማጥፋትህ በፊት፤ የAndroid USB ማከማቻህን ከኮምውተርህ ንቀል (\"አውጣ\")።"</string>
+    <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"USB ማከማቻን ከማጥፋትዎ በፊት፤ የAndroid USB ማከማቻዎን ከኮምውተርዎ ይንቀሉ (\"ያውጡ\")።"</string>
     <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"የUSB ማከማቻ ከማጥፋት በፊት የAndroid SD ካርድህን ከኮምፒዩተርህ ላይ ንቀል(“አውጣ”)።"</string>
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB ማከማቻ አጥፋ"</string>
     <string name="usb_storage_stop_error_message" msgid="1970374898263063836">"የ USB ማከማቻ ለማጥፋት ችግር ነበር። USB አስተናጋጅ መንቀልህን አረጋግጥ፤ ከዛም እንደገና ሞክር።"</string>
@@ -1380,7 +1387,7 @@
     <string name="storage_usb" msgid="3017954059538517278">"የUSB  ማከማቻ"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"የውሂብ አጠቃቀም ማስጠንቀቂየ"</string>
-    <string name="data_usage_warning_body" msgid="2814673551471969954">"ቅንጅቶችን እና አጠቃቀምን ለማየት ንካ።"</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"ቅንብሮችን እና አጠቃቀምን ለማየት ይንኩ።"</string>
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G-3G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G ውሂብ ቦዝኗል"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"የተንቀሳቃሽ ውሂብ ቦዝኗል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d134ca4..0c611cd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"إعادة تشغيل"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"تعرض الصفحة في \"<xliff:g id="TITLE">%s</xliff:g>\":"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"جافا سكريبت"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"هل تريد الانتقال بعيدًا عن هذه الصفحة؟"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"المس \"موافق\" للمتابعة، أو \"إلغاء\" للبقاء في الصفحة الحالية."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"تأكيد"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"نصيحة: اضغط مرتين للتكبير والتصغير."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ملء تلقائي"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 9f3d3e6..eb2033c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перазагрузіць"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"На старонцы з адрасам <xliff:g id="TITLE">%s</xliff:g> вызначана:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Пакiнуць гэту старонку?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Націсніце \"OK\", каб працягнуць, або \"Адмена\", каб застацца на бягучай старонцы."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0983b5e..27a0f59 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Рестартиране"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Страницата на адрес „<xliff:g id="TITLE">%s</xliff:g>“ съобщава:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Искате ли да напуснете тази страница?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Докоснете „OK“, за да продължите, или „Отказ“, за да останете на нея."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Потвърждение"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Съвет: Докоснете двукратно, за да увеличите или намалите мащаба."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автопоп."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index ccea866..4e68a6b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reinicia"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pàgina de \"<xliff:g id="TITLE">%s</xliff:g>\" diu:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vols sortir d\'aquesta pàgina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona D\'acord per continuar o Cancel·la per seguir a la pàgina actual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consell: Pica dos cops per ampliar i per reduir."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Em. aut."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c9a84cb..c92d249 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -155,7 +155,7 @@
     <string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"Zaznamenat zprávu o chybě"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Tichý režim"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je VYPNUTÝ."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Restartovat"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Chcete-li pokračovat, dotkněte se možnosti OK. Chcete-li zůstat na aktuální stránce, dotkněte se možnosti Zrušit."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím můžete zobrazení přiblížit nebo oddálit."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.vyp."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0c7cf72..29a5776 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid fra, at fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lydløs"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Lyden er slået FRA"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Lyden er TIL"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Genstart"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"På siden på \"<xliff:g id="TITLE">%s</xliff:g>\" står der:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du gå væk fra denne side?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryk på OK for at fortsætte eller Annuller for at blive på den aktuelle side."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip! Dobbeltklik for at zoome ind eller ud."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyld"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c03aa70..dcf27e3 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Neustart"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Auf der Seite \"<xliff:g id="TITLE">%s</xliff:g>\" steht:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Diese Seite verlassen?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tippen Sie zum Fortfahren auf \"OK\" oder tippen Sie auf \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: Zum Vergrößern und Verkleinern zweimal tippen"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"AutoFill"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6dcdbf1..414111d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Επανεκκίνηση"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Η σελίδα στον τίτλο \"<xliff:g id="TITLE">%s</xliff:g>\" λέει:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Απομάκρυνση από αυτή τη σελίδα;"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Αγγίξτε το στοιχείο \"OK\" για συνέχεια ή \"Ακύρωση\" για παραμονή στην τρέχουσα σελίδα."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Συμβουλή: Πατήστε δύο φορές για μεγέθυνση και σμίκρυνση."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Αυτόματη συμπλήρωση"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 08283c4..d95c1d9 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reboot"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"The page at \"<xliff:g id="TITLE">%s</xliff:g>\" says:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigate away from this page?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Touch OK to continue or Cancel to stay on the current page."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirm"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: double-tap to zoom in and out."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Auto-fill"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 98528f7..5005d41 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -773,7 +773,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Presionar Menú para desbloquear."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dibujar el patrón de desbloqueo"</string>
-    <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Llamada de emergencia"</string>
+    <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Realizar llamada de emergencia"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Regresar a llamada"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correcto"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Vuelve a intentarlo."</string>
@@ -783,7 +783,7 @@
     <string name="lockscreen_charged" msgid="321635745684060624">"Cargado"</string>
     <string name="lockscreen_battery_short" msgid="4477264849386850266">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
-    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"No hay tarjeta SIM."</string>
+    <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Sin tarjeta SIM"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el dispositivo."</string>
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
@@ -795,7 +795,7 @@
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Botón Pausa"</string>
     <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"Botón Reproducir"</string>
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"Botón Detener"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"Sólo llamadas de emergencia"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"Solo llamadas de emergencia"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Red bloqueada"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"La tarjeta SIM está bloqueada con PUK."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consulta la guía del usuario o comunícate con el servicio de atención al cliente."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toca Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Consejo: Toca dos veces para acercar y alejar la imagen."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1437,7 +1444,7 @@
     <string name="wifi_display_notification_title" msgid="2223050649240326557">"Se conectó la pantalla inalámbrica"</string>
     <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
-    <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
     <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 485e1bf..d20f7fa 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toca Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sugerencia: toca dos veces para ampliar o reducir el contenido."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autocompletar"</string>
@@ -1195,7 +1202,7 @@
     <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si activas el almacenamiento USB, se detendrán algunas aplicaciones que estás usando y es posible que no estén disponibles hasta que lo desactives."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Error de funcionamiento de USB"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
-    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como disp. multimedia"</string>
+    <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como dispositivo multimedia"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index d2d4d63..c30e2a9 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Taaskäivita"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Leht  „<xliff:g id="TITLE">%s</xliff:g>” ütleb järgmist."</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage valikut OK, praegusele lehele jäämiseks valikut Tühista."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Kinnita"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f723c37..f254b52 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -622,7 +622,7 @@
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"اعلان‌های دسترسی"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه می‌دهد به بازیابی، بررسی و پاک کردن اعلان‌ها از جمله موارد پست شده توسط سایر برنامه‌ها بپردازد."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. این هرگز برای برنامه‌های عادی ضروری نیست."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه می‌دهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامه‌های عادی لازم شود."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسه‎های مجاز در گذرواژه‌های بازکردن قفل صفحه را کنترل کنید."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"راه‌اندازی مجدد"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"صفحه در \"<xliff:g id="TITLE">%s</xliff:g>\" می‎گوید:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"جاوا اسکریپت"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"از این صفحه خارج می‎شوید؟"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"برای ادامه روی تأیید و برای ماندن در همین صفحه روی لغو کلیک کنید."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"تأیید"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"نکته: برای بزرگنمایی و کوچکنمایی، دو بار ضربه بزنید."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"تکمیل خودکار"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7f7f07a..f75d474 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Käynnistä uudelleen"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Sivu <xliff:g id="TITLE">%s</xliff:g> sanoo:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Siirrytäänkö pois tältä sivulta?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Valitse OK, jos haluat jatkaa, tai Peruuta, jos et halua siirtyä pois sivulta."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Vahvista"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Vinkki: lähennä ja loitonna kaksoisnapauttamalla."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut. täyttö"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 65c4ce5..4a87fd0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Redémarrer"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" indique :"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Voulez-vous quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Appuyez sur \"OK\" pour continuer ou \"Annuler\" pour rester sur la page actuelle."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Conseil : Appuyez deux fois pour faire un zoom avant ou arrière."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Saisie auto"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 79dbfff..b922e401 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पृष्ठ दर्शाता है:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"इस पृष्ठ से दूर नेविगेट करें?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"जारी रखने के लिए ठीक को चुनें, या वर्तमान पृष्ठ पर रहने के लिए रद्द करें को चुनें."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"पुष्टि करें"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"युक्ति: ज़ूम इन और आउट करने के लिए डबल-टैप करें."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"स्‍वत: भरण"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 90b44d2..128b48c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Ponovno pokreni"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Stranica na adresi \"<xliff:g id="TITLE">%s</xliff:g>\" sadrži sljedeće:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Želite otići s ove lokacije?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Za nastavak dodirnite U redu, a za ostanak na trenutačnoj stranici dodirnite Odustani."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Savjet: Dvaput dotaknite za povećavanje i smanjivanje."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.pop."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index d71ac23..0e0f13a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Újraindítás"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"A \"<xliff:g id="TITLE">%s</xliff:g>\" címen található oldal szerint:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Elhagyja ezt az oldalt?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"A folytatáshoz érintse meg az OK, a jelenlegi oldalon maradáshoz a Mégse lehetőséget."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Megerősítés"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tipp: érintse meg kétszer a nagyításhoz és kicsinyítéshez."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Kitöltés"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index a9b33de..fd04f2a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Mulai ulang"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Laman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Beranjak dari laman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh Oke untuk melanjutkan atau Batal untuk tetap pada laman ini."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Isiotomatis"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 560b049..7cda28a 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -440,16 +440,16 @@
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"aggiunta o modifica di eventi di calendario e invio di email agli ospiti a insaputa dei proprietari"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul tablet, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Consente all\'applicazione di aggiungere, rimuovere, modificare gli eventi che puoi modificare sul telefono, inclusi quelli di amici o colleghi. Ciò potrebbe consentire all\'applicazione di inviare messaggi apparentemente provenienti dai proprietari del calendario o di modificare eventi all\'insaputa dei proprietari."</string>
-    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di localizzazione fittizie per test"</string>
-    <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Crea fonti di localizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di localizzazione, come il GPS o fornitori di posizione."</string>
+    <string name="permlab_accessMockLocation" msgid="8688334974036823330">"fonti di geolocalizzazione fittizie per test"</string>
+    <string name="permdesc_accessMockLocation" msgid="5808711039482051824">"Crea fonti di geolocalizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di geolocalizzazione, come il GPS o fornitori di posizione."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi del provider di localizz."</string>
-    <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Consente all\'applicazione di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'applicazione di interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="5945166642335800763">"Consente all\'applicazione di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'applicazione di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"autorizzazione a installare un provider di localizzazione"</string>
-    <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Crea fonti di localizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di localizzazione, come il GPS o fornitori di posizione."</string>
+    <string name="permdesc_installLocationProvider" msgid="9066146120470591509">"Crea fonti di geolocalizzazione fittizie per i test o installa un nuovo fornitore di posizione. Ciò consente all\'applicazione di ignorare la posizione e/o lo stato restituito da altre fonti di geolocalizzazione, come il GPS o fornitori di posizione."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"posizione precisa (GPS e basata sulla rete)"</string>
-    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di localizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
+    <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Consente all\'applicazione di ottenere la tua posizione esatta utilizzando il sistema GPS (Global Positioning System) o fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione e potrebbero consumare ulteriore batteria."</string>
     <string name="permlab_accessCoarseLocation" msgid="4887895362354239628">"posizione approssimativa (basata sulla rete)"</string>
-    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di localizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
+    <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"accesso a SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Consente all\'applicazione l\'utilizzo di funzioni di basso livello SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"lettura buffer di frame"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Riavvia"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pagina all\'indirizzo \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tocca OK per continuare o Annulla per rimanere nella pagina corrente."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Suggerimento. Tocca due volte per aumentare e diminuire lo zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Compilazione autom."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 42f0e2d..59b4f65 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"אתחל מחדש"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"בדף שבכתובת \'<xliff:g id="TITLE">%s</xliff:g>\' כתוב כך:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"לנווט אל מחוץ לדף זה?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"גע באפשרות \'אישור\' כדי להמשיך, או \'ביטול\' כדי להישאר בדף הנוכחי."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"אשר"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"טיפ: הקש פעמיים כדי להגדיל ולהקטין."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"מילוי אוטומטי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f6b93f9..4fafb60 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"再起動"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"<xliff:g id="TITLE">%s</xliff:g> のページ:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"このページから移動しますか?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"移動する場合は[OK]、現在のページに留まる場合は[キャンセル]をタップしてください。"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"ヒント: ダブルタップで拡大/縮小できます。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自動入力"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5f50ac4..df40880 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"다시 부팅"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"자바스크립트"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"다른 페이지를 탐색하시겠습니까?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계속하려면 \'확인\'을 터치하고 현재 페이지에 그대로 있으려면 \'취소\'를 터치하세요."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"확인"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"도움말: 확대/축소하려면 두 번 탭합니다."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"자동완성"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9237a2c..ed31762 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Pakartotinai įkelti"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Puslapyje šiuo adresu: <xliff:g id="TITLE">%s</xliff:g>, teigiama:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Išeiti iš šio puslapio?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Palieskite „Gerai“, jei norite tęsti, arba palieskite „Atšaukti“, jei norite likti dabartiniame puslapyje."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Patvirtinti"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Patarimas: palieskite dukart, kad padidintumėte ar sumažintumėte mastelį."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automatinis pildymas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1de841e..3f30242 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Atsāknēt"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Lapā <xliff:g id="TITLE">%s</xliff:g> ir teikts:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vai doties prom no šīs lapas?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Pieskarieties Labi, lai turpinātu, vai Atcelt, lai paliktu pašreizējā lapā."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Apstiprināt"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Padoms. Divreiz pieskarieties, lai tuvinātu un tālinātu."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automātiskā aizpilde"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index af5b866..5f49ed3 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"But semula"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Halaman di \'<xliff:g id="TITLE">%s</xliff:g>\' berkata:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navigasi keluar dari halaman ini?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sentuh OK untuk meneruskan, atau Batal untuk terus berada di halaman semasa."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Sahkan"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Petua: Ketik dua kali untuk mengezum masuk dan keluar."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Auto isi"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e0d9bf2..a81f017 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Omstart"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Siden på «<xliff:g id="TITLE">%s</xliff:g>» sier:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vil du navigere bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Trykk på OK for å fortsette eller på Avbryt for å bli værende på siden."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tips: Dobbelttrykk for å zoome inn og ut."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2e92761..0558096 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Opnieuw opstarten"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' meldt het volgende:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies \'OK\' om door te gaan of \'Annuleren\' om op de huidige pagina te blijven."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: dubbeltik om in en uit te zoomen."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autom. aanvullen"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d8a4bf9..2fa77a9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Uruchom ponownie"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>”:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Dotknij OK, aby kontynuować, lub Anuluj, aby pozostać na tej stronie."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Wskazówka: dotknij dwukrotnie, aby powiększyć lub pomniejszyć."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autouzupełnianie"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 66d50e6..edb3414 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -144,7 +144,7 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ativada"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"O seu tablet irá encerrar."</string>
-    <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone irá encerrar."</string>
+    <string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será encerrado."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Pretende encerrar?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
     <string name="reboot_safemode_confirm" msgid="55293944502784668">"Pretende reiniciar no modo de segurança? Se sim, irá desativar todas as aplicações de terceiros instaladas. Estas serão restauradas quando reiniciar novamente."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" indica:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Navegar para outra página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Toque em OK para continuar ou Cancelar para permanecer na página atual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sugestão: toque duas vezes para aumentar ou diminuir o zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Preenchimento Automático"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3877158..184f704 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -160,9 +160,9 @@
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Som DESATIVADO"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"O som está ATIVADO"</string>
-    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
-    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo de avião ATIVADO"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo de avião DESATIVADO"</string>
+    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
+    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reiniciar"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"A página em \"<xliff:g id="TITLE">%s</xliff:g>\" diz:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Deseja sair desta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecione OK para continuar ou Cancelar para permanecer na página atual."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Preench. aut."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index ba863cb..7d10377 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1398,7 +1398,13 @@
     <!-- no translation found for js_dialog_title (1987483977834603872) -->
     <skip />
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <!-- no translation found for js_dialog_before_unload (730366588032430474) -->
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
     <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confermar"</string>
     <!-- no translation found for double_tap_toast (4595046515400268881) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 21fcf04..bad14405 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -622,7 +622,7 @@
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"accesare notificări"</string>
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string>
-    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
+    <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reporniţi"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"La pagina de la „<xliff:g id="TITLE">%s</xliff:g>” apare:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Doriţi să părăsiţi această pagină?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Apăsaţi pe OK pentru a continua sau pe Anulaţi pentru a rămâne pe pagina curentă."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confirmaţi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi şi micşoraţi prin dublă atingere."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 592271b..d9bf3e2c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перезагрузка"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Подтвердите действие на <xliff:g id="TITLE">%s</xliff:g>"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Покинуть эту страницу?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Совет: нажмите дважды, чтобы увеличить и уменьшить масштаб."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автозаполнение"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 228a9e7..caedb22 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reštartovať"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Stránka „<xliff:g id="TITLE">%s</xliff:g>“ uvádza:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Chcete opustiť túto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Ak chcete pokračovať, dotknite sa tlačidla OK. Ak chcete zostať na stránke, dotknite sa tlačidla Zrušiť."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potvrdiť"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Dvojitým klepnutím môžete zobrazenie priblížiť alebo oddialiť."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Aut.dop."</string>
@@ -1051,7 +1058,7 @@
     <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nedostatok ukladacieho priestoru"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Niektoré systémové funkcie nemusia fungovať"</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená"</string>
-    <string name="app_running_notification_text" msgid="4653586947747330058">"Dotknutím sa zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
+    <string name="app_running_notification_text" msgid="4653586947747330058">"Dotykom si zobrazíte viac informácií alebo zastavíte aplikáciu."</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 906c197..64df433 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Znova zaženi"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Na strani na »<xliff:g id="TITLE">%s</xliff:g>« piše:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Ali se želite premakniti s te strani"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Če želite nadaljevati, se dotaknite »V redu«, če želite ostati na trenutni strani, izberite »Prekliči«."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Potrdi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Nasvet: Tapnite dvakrat, če želite povečati ali pomanjšati."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Samoizp."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 102ced6..ec0384c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Поново покрени"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"На страници на адреси „<xliff:g id="TITLE">%s</xliff:g>“ пише следеће:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Желите ли да напустите ову страницу?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Додирните Потврди да бисте наставили или Откажи да бисте остали на тренутно отвореној страници."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Потврда"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Савет: Додирните двапут да бисте увећали и умањили приказ."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Аутом. поп."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index adeffc3..7993bf8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Starta om"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"På sidan på <xliff:g id="TITLE">%s</xliff:g> står det:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Vill du lämna den här den här sidan?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Tryck på OK om du vill fortsätta eller på Avbryt om du vill vara kvar på den aktuella sidan."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tips! Dubbelknacka om du vill zooma in eller ut."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofyll"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bdc0155..535b805 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -138,7 +138,7 @@
     <string name="turn_on_radio" msgid="3912793092339962371">"Washa mtandao-hewa"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Zima pasiwaya"</string>
     <string name="screen_lock" msgid="799094655496098153">"Funga skrini"</string>
-    <string name="power_off" msgid="4266614107412865048">"Nishati imezimwa"</string>
+    <string name="power_off" msgid="4266614107412865048">"Zima simu"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Programu ya milio imezimwa"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Mtetemo wa programu ya milio"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
@@ -153,7 +153,7 @@
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Chaguo za kompyuta ndogo"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
-    <string name="global_action_power_off" msgid="4471879440839879722">"Nishati imezimwa"</string>
+    <string name="global_action_power_off" msgid="4471879440839879722">"Zima simu"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali yako ya sasa ya kifaa, ili kutuma ujumbe wa barua pepe. Itachukua muda mfupi kuanza ripoti ya hitilafu mpaka itakapokuwa tayari kutumwa; tafadhali vumilia."</string>
@@ -519,7 +519,7 @@
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zuia simu dhidi ya kulala"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao  kwenda kulala."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Inaruhusu programu kuzuia simu isiende kulala."</string>
-    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta ndogo"</string>
+    <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Washa au zima kompyuta kibao"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"washa au zima simu"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Inaruhusu programu kuwasha au kuzima kompyuta kibao."</string>
     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Inaruhusu programu kuwasha au kuzima simu."</string>
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Washa tena"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Ukurasa ulio \"<xliff:g id="TITLE">%s</xliff:g>\" unasema:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"HatiJava"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Toka kwa ukurasa huu?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Gusa Sawa ili kuendelea, au Ghairi ili kubaki kwenye ukurasa wa sasa."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Thibitisha"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kidokezo: Gonga mara mbili ili kukuza ndani na nje."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Kujaza kiotomatiki"</string>
@@ -1060,7 +1067,7 @@
     <string name="loading" msgid="7933681260296021180">"Inapakia…"</string>
     <string name="capital_on" msgid="1544682755514494298">"Washa"</string>
     <string name="capital_off" msgid="6815870386972805832">"ZIMA"</string>
-    <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo kwa kutumia"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Kamilisha kitendo ukitumia"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Tumia kama chaguo-msingi la kitendo hiki."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Futa chaguo-msingi katika mipangilio ya Mfumo &gt; Apps &gt; iliyopakuliwa."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Chagua kitendo"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a92db72..1c97cb0d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"รีบูต"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"หน้าเว็บที่ \"<xliff:g id="TITLE">%s</xliff:g>\" ระบุว่า:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"ไปจากหน้าเว็บนี้หรือไม่"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"แตะ \"ตกลง\" เพื่อทำต่อ หรือ \"ยกเลิก\" เพื่ออยู่ที่หน้าเว็บปัจจุบัน"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"ยืนยัน"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"เคล็ดลับ: แตะสองครั้งเพื่อขยายและย่อ"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"ป้อนอัตโนมัติ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e726333..45a5410 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"I-reboot"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Isinasaad ng pahina sa \"<xliff:g id="TITLE">%s</xliff:g>\" na:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Mag-navigate palayo mula sa pahinang ito?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Pindutin ang OK upang magpatuloy, o Kanselahin upang manatili sa kasalukuyang pahina."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Kumpirmahin"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Tip: Mag-double tap upang mag-zoom in at out."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Autofill"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 9e5e43b..77b1cc6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Yeniden başlat"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"\"<xliff:g id="TITLE">%s</xliff:g>\" adresindeki sayfada şunlar belirtiliyor:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Bu sayfadan ayrılıyor musunuz?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Devam etmek için Tamam\'ı, mevcut sayfada kalmak için İptal\'i tıklayın."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe vurun."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Otomatik Doldur"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bb223ea..0cdedc1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перезав."</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"На сторінці за адресою \"<xliff:g id="TITLE">%s</xliff:g>\" написано:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"Javascript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Перейти з цієї сторінки?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Торкніться \"OK\", щоб продовжити, або \"Скасувати\", щоб залишитися на поточній сторінці."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Підтверд."</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Порада: двічі торкніться для збільшення чи зменшення."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Автозап."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a592144..7732f4a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Khởi động lại"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Trang tại \"<xliff:g id="TITLE">%s</xliff:g>\" cho biết:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Điều hướng khỏi trang này?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Chạm OK để tiếp tục hoặc Hủy để ở lại trang hiện tại."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Xác nhận"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Mẹo: Nhấn đúp để phóng to và thu nhỏ."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Tự động điền"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 79c79f3..9d1c48c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"重新启动"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"网址为“<xliff:g id="TITLE">%s</xliff:g>”的网页显示:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"要从此页面导航至其他页面吗?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"触摸“确定”继续,或触摸“取消”留在当前页面。"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"确认"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"提示:点按两次可放大或缩小。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自动填充"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dfd91a4..b4c41b4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"重新開機"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"「<xliff:g id="TITLE">%s</xliff:g>」網頁指出:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"離開這個頁面?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"輕觸 [確定] 離開這個頁面,或輕觸 [取消] 停留在這個頁面。"</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"確認"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"提示:輕按兩下即可縮放。"</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"自動填入功能"</string>
@@ -1475,7 +1482,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"移除"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽偏高音量可能會損害您的聽力。"</string>
+    <string name="safe_media_volume_warning" product="default" msgid="7324161939475478066">"要將音量調高到建議等級以上嗎?"\n"長時間聆聽高音量可能會損害您的聽力。"</string>
     <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持續用兩指按住即可啟用協助工具。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 41ac207..e2f1478 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -864,7 +864,14 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Qalisa kabusha"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"Ikhasi eliku <xliff:g id="TITLE">%s</xliff:g> lithi:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"i-JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Phuma kuleli khasi? "\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" Thinta KULUNGILE ukuqhubeka, noma Khansela ukuhlala kuleli khasi."</string>
+    <!-- no translation found for js_dialog_before_unload_title (2619376555525116593) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_positive_button (3112752010600484130) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload_negative_button (5614861293026099715) -->
+    <skip />
+    <!-- no translation found for js_dialog_before_unload (3468816357095378590) -->
+    <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Qinisekisa"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Ithiphu: thepha kabili ukusondeza ngaphandle nangaphakathi."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Ukugcwalisa Ngokuzenzakalelayo"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c7a374..60f3f32 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2521,13 +2521,43 @@
             <flag name="flagRequestTouchExplorationMode" value="0x00000004" />
             <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} -->
             <flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} -->
+            <flag name="flagReportViewIds" value="0x00000010" />
+            <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} -->
+            <flag name="flagRequestFilterKeyEvents" value="0x00000020" />
         </attr>
         <!-- Component name of an activity that allows the user to modify
              the settings for this service. This setting cannot be changed at runtime. -->
         <attr name="settingsActivity" />
-        <!-- Flag whether the accessibility service wants to be able to retrieve the
+        <!-- Attribute whether the accessibility service wants to be able to retrieve the
              active window content. This setting cannot be changed at runtime. -->
         <attr name="canRetrieveWindowContent" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to request touch
+             exploration mode in which touched items are spoken aloud and the UI can be
+             explored via gestures.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} flag.
+             </p>
+         -->
+        <attr name="canRequestTouchExplorationMode" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to request enhanced
+             web accessibility enhancements. For example, installing scripts to make app
+             content more accessible.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} flag.
+             </p>
+         -->
+        <attr name="canRequestEnhancedWebAccessibility" format="boolean" />
+        <!-- Attribute whether the accessibility service wants to be able to request to
+             filter key events.
+             <p>
+             Required to allow setting the {@link android.accessibilityservice
+             #AccessibilityServiceInfo#FLAG_REQUEST_FILTER_KEY_EVENTS} flag.
+             </p>
+         -->
+        <attr name="canRequestFilterKeyEvents" format="boolean" />
         <!-- Short description of the accessibility serivce purpose or behavior.-->
         <attr name="description" />
     </declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cc50d8a..84e300a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -345,6 +345,12 @@
          A value of -1 means no change in orientation by default. -->
     <integer name="config_carDockRotation">-1</integer>
 
+    <!-- The number of degrees to rotate the display when the device has HDMI connected
+         but is not in a dock.  A value of -1 means no change in orientation by default.
+         Use -1 except on older devices whose Hardware Composer HAL does not
+         provide full support for multiple displays.  -->
+    <integer name="config_undockedHdmiRotation">-1</integer>
+
     <!-- Control the default UI mode type to use when there is no other type override
          happening.  One of the following values (See Configuration.java):
              1  UI_MODE_TYPE_NORMAL
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 074d91f..c150fe0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2043,10 +2043,10 @@
   <public type="attr" name="childIndicatorEnd" />
   <public type="attr" name="restrictedAccountType" />
   <public type="attr" name="requiredAccountType" />
+  <public type="attr" name="canRequestTouchExplorationMode" />
+  <public type="attr" name="canRequestEnhancedWebAccessibility" />
+  <public type="attr" name="canRequestFilterKeyEvents" />
 
-  <public type="style" name="Theme.NoTitleBar.Overscan" />
-  <public type="style" name="Theme.Light.NoTitleBar.Overscan" />
-  <public type="style" name="Theme.Black.NoTitleBar.Overscan" />
   <public type="style" name="Theme.Holo.NoActionBar.Overscan" />
   <public type="style" name="Theme.Holo.Light.NoActionBar.Overscan" />
   <public type="style" name="Theme.DeviceDefault.NoActionBar.Overscan" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3361ab7..db9602a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -545,6 +545,31 @@
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_accessibilityFeatures">Features that assistive technology can request.</string>
 
+    <!-- Title for the capability of an accessibility service to retrieve window content. -->
+    <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
+    <!-- Description for the capability of an accessibility service to retrieve window content. -->
+    <string name="capability_desc_canRetrieveWindowContent">Inspect the content of a window you\'re
+        interacting with.</string>
+
+    <!-- Title for the capability of an accessibility service to request touch exploration. -->
+    <string name="capability_title_canRequestTouchExploration">Turn on Explore by Touch</string>
+    <!-- Description for the capability of an accessibility service to request touch exploration. -->
+    <string name="capability_desc_canRequestTouchExploration">Touched items will be spoken aloud
+        and the screen can be explored using gestures.</string>
+
+    <!-- Title for the capability of an accessibility service to request enhanced web accessibility. -->
+    <string name="capability_title_canRequestEnhancedWebAccessibility">Turn on enhanced web
+        accessibility</string>
+    <!-- Description for the capability of an accessibility service to request enhanced web accessibility. -->
+    <string name="capability_desc_canRequestEnhancedWebAccessibility">Scripts may be installed to
+        make app content more accessible.</string>
+
+    <!-- Title for the capability of an accessibility service to request to filter key events. -->
+    <string name="capability_title_canRequestFilterKeyEvents">Observe text you type</string>
+    <!-- Description for the capability of an accessibility service to request to filter key events. -->
+    <string name="capability_desc_canRequestFilterKeyEvents">Includes personal data such as credit
+        card numbers and passwords.</string>
+
     <!--  Permissions -->
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -945,20 +970,6 @@
         interface of an accessibility service. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_canRequestTouchExplorationMode">request explore by touch</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_canRequestTouchExplorationMode">Allows the hoder to request an
-        interaction mode in which touched items are spoken aloud and the UI can be explored
-        via gestures.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_canRequestEnahncedWebAccessibility">request enhanced web accessibility</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_canRequestEnahncedWebAccessibility">Allows the hoder to request
-        enabling of web accessibility enhancements. For example, installing scripts to make
-        app content more accessible.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindTextService">bind to a text service</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 45ea182..fdf7c8f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -438,6 +438,14 @@
   <java-symbol type="string" name="badPin" />
   <java-symbol type="string" name="badPuk" />
   <java-symbol type="string" name="byteShort" />
+  <java-symbol type="string" name="capability_desc_canRequestEnhancedWebAccessibility" />
+  <java-symbol type="string" name="capability_title_canRequestFilterKeyEvents" />
+  <java-symbol type="string" name="capability_desc_canRequestTouchExploration" />
+  <java-symbol type="string" name="capability_desc_canRetrieveWindowContent" />
+  <java-symbol type="string" name="capability_title_canRequestEnhancedWebAccessibility" />
+  <java-symbol type="string" name="capability_desc_canRequestFilterKeyEvents" />
+  <java-symbol type="string" name="capability_title_canRequestTouchExploration" />
+  <java-symbol type="string" name="capability_title_canRetrieveWindowContent" />
   <java-symbol type="string" name="cfTemplateForwarded" />
   <java-symbol type="string" name="cfTemplateForwardedTime" />
   <java-symbol type="string" name="cfTemplateNotForwarded" />
@@ -1584,6 +1592,7 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
+  <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
   <java-symbol type="layout" name="launch_warning" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e1750af..80f7486 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -405,16 +405,6 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Variant of {@link #Theme} that has no title bar and no status bar and extending
-        into the display overscan region.  This theme
-        sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-        to true. -->
-    <style name="Theme.NoTitleBar.Overscan">
-        <item name="android:windowFullscreen">true</item>
-        <item name="android:windowOverscan">true</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
-
     <!-- Theme for a light background with dark text on top.  Set your activity
          to this theme if you would like such an appearance.  As with the
          default theme, you should try to assume little more than that the
@@ -508,16 +498,6 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Variant of {@link #Theme_Light} that has no title bar and
-         no status bar and extending into the display overscan region.  This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Light.NoTitleBar.Overscan">
-        <item name="android:windowFullscreen">true</item>
-        <item name="android:windowOverscan">true</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
-
     <!-- Variant on {@link #Theme} that ensures the background is
          completely black.  This is useful for things like image viewers and
          media players.   If you want the normal (dark background) theme
@@ -539,16 +519,6 @@
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
-    
-    <!-- Variant of {@link #Theme_Black} that has no title bar and
-         no status bar and extending into the display overscan region.  This theme
-         sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
-         to true. -->
-    <style name="Theme.Black.NoTitleBar.Overscan">
-        <item name="android:windowFullscreen">true</item>
-        <item name="android:windowOverscan">true</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
 
     <!-- Theme for windows that want to have the user's selected
          wallpaper appear behind them (for API level 10 and lower).  -->
diff --git a/data/keyboards/Vendor_0079_Product_0011.kl b/data/keyboards/Vendor_0079_Product_0011.kl
new file mode 100644
index 0000000..2ae2a01
--- /dev/null
+++ b/data/keyboards/Vendor_0079_Product_0011.kl
@@ -0,0 +1,23 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Classic NES Controller
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl
index 99f046a..ca6fa59 100644
--- a/data/keyboards/Vendor_045e_Product_028e.kl
+++ b/data/keyboards/Vendor_045e_Product_028e.kl
@@ -22,9 +22,9 @@
 key 308   BUTTON_Y
 key 310   BUTTON_L1
 key 311   BUTTON_R1
-key 314   BUTTON_SELECT
+key 314   BUTTON_BACK
 key 315   BUTTON_START
-key 316   BUTTON_MODE
+key 316   BUTTON_HOME
 key 317   BUTTON_THUMBL
 key 318   BUTTON_THUMBR
 
diff --git a/data/keyboards/Vendor_046d_Product_c219.kl b/data/keyboards/Vendor_046d_Product_c219.kl
new file mode 100644
index 0000000..431dd03
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c219.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Logitech Logitech Cordless RumblePad 2
+
+key 305 BUTTON_A
+key 306 BUTTON_B
+key 304 BUTTON_X
+key 307 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 310 BUTTON_L2
+key 311 BUTTON_R2
+key 313 BUTTON_START
+key 312 BUTTON_BACK
+key 314 BUTTON_THUMBL
+key 315 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_046d_Product_c21f.kl b/data/keyboards/Vendor_046d_Product_c21f.kl
new file mode 100644
index 0000000..981d864
--- /dev/null
+++ b/data/keyboards/Vendor_046d_Product_c21f.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Logitech Wireless Gamepad F710
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_054c_Product_0268.kl b/data/keyboards/Vendor_054c_Product_0268.kl
index f8ac6a3..62c5f4d5 100644
--- a/data/keyboards/Vendor_054c_Product_0268.kl
+++ b/data/keyboards/Vendor_054c_Product_0268.kl
@@ -23,10 +23,10 @@
 
 key 0x120    BUTTON_SELECT
 key 0x123    BUTTON_START
-key 0x12f    BUTTON_A
-key 0x12c    BUTTON_B
-key 0x12e    BUTTON_X
-key 0x12d    BUTTON_Y
+key 0x12e    BUTTON_A
+key 0x12d    BUTTON_B
+key 0x12f    BUTTON_X
+key 0x12c    BUTTON_Y
 key 0x12a    BUTTON_L1
 key 0x12b    BUTTON_R1
 key 0x128    BUTTON_L2
@@ -35,7 +35,7 @@
 key 0x122    BUTTON_THUMBR
 
 # PS key
-key 0x2d0    BUTTON_1
+key 0x2d0    BUTTON_HOME
 
 # Left Analog Stick
 axis 0x00    X
diff --git a/data/keyboards/Vendor_0583_Product_2060.kl b/data/keyboards/Vendor_0583_Product_2060.kl
new file mode 100644
index 0000000..92c8a14
--- /dev/null
+++ b/data/keyboards/Vendor_0583_Product_2060.kl
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ION GO PAD
+
+key 288 BUTTON_A
+key 289 BUTTON_B
+key 290 BUTTON_X
+key 291 BUTTON_Y
+key 294 BUTTON_L1
+key 295 BUTTON_R1
+key 292 BUTTON_L2
+key 293 BUTTON_R2
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl
new file mode 100644
index 0000000..0084969
--- /dev/null
+++ b/data/keyboards/Vendor_0a5c_Product_8502.kl
@@ -0,0 +1,33 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Snakebyte
+
+key 289 BUTTON_A
+key 290 BUTTON_B
+key 288 BUTTON_X
+key 291 BUTTON_Y
+key 292 BUTTON_L1
+key 293 BUTTON_R1
+key 294 BUTTON_L2
+key 295 BUTTON_R2
+key 297 BUTTON_START
+key 296 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1038_Product_1412.kl b/data/keyboards/Vendor_1038_Product_1412.kl
new file mode 100644
index 0000000..551b0bd
--- /dev/null
+++ b/data/keyboards/Vendor_1038_Product_1412.kl
@@ -0,0 +1,31 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Steelseries Free
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 316 BUTTON_SELECT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_12bd_Product_d015.kl b/data/keyboards/Vendor_12bd_Product_d015.kl
new file mode 100644
index 0000000..557d62f
--- /dev/null
+++ b/data/keyboards/Vendor_12bd_Product_d015.kl
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Hitgaming SNES Retro
+
+key 306 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 304 BUTTON_Y
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 313 BUTTON_START
+key 312 BUTTON_SELECT
+
+axis 0x00 HAT_X
+axis 0x01 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fd00.kl b/data/keyboards/Vendor_1689_Product_fd00.kl
new file mode 100644
index 0000000..6ce14ed
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd00.kl
@@ -0,0 +1,38 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Razer Onza Tournament Edition
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 307 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+key 706 DPAD_UP
+key 705 DPAD_RIGHT
+key 707 DPAD_DOWN
+key 704 DPAD_LEFT
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
diff --git a/data/keyboards/Vendor_1689_Product_fd01.kl b/data/keyboards/Vendor_1689_Product_fd01.kl
new file mode 100644
index 0000000..8144515
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fd01.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Razer Xbox 360 Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 308 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1689_Product_fe00.kl b/data/keyboards/Vendor_1689_Product_fe00.kl
new file mode 100644
index 0000000..90fe4af
--- /dev/null
+++ b/data/keyboards/Vendor_1689_Product_fe00.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Razer Sabertooth Elite
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f016.kl b/data/keyboards/Vendor_1bad_Product_f016.kl
new file mode 100644
index 0000000..b72fd5ce
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f016.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Madcatz Gamepad
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f023.kl b/data/keyboards/Vendor_1bad_Product_f023.kl
new file mode 100644
index 0000000..c1588b2
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f023.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Mad Catz MLG GamePad for Xbox 360
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f027.kl b/data/keyboards/Vendor_1bad_Product_f027.kl
new file mode 100644
index 0000000..ea0aa7a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f027.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# MadCatz FPS Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1bad_Product_f036.kl b/data/keyboards/Vendor_1bad_Product_f036.kl
new file mode 100644
index 0000000..8cd906a
--- /dev/null
+++ b/data/keyboards/Vendor_1bad_Product_f036.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# MadCatz Generic XBox Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_BACK
+key 316 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_1d79_Product_0009.kl b/data/keyboards/Vendor_1d79_Product_0009.kl
new file mode 100644
index 0000000..78fe2cd
--- /dev/null
+++ b/data/keyboards/Vendor_1d79_Product_0009.kl
@@ -0,0 +1,36 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Nyko Playpad / Playpad Pro
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 158 BUTTON_BACK
+key 172 BUTTON_HOME
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl
new file mode 100644
index 0000000..d9cd171
--- /dev/null
+++ b/data/keyboards/Vendor_2378_Product_100a.kl
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# OnLive, Inc. OnLive Wireless Controller
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BUTTON_SELECT
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+axis 0x05 RTRIGGER
+axis 0x02 LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
diff --git a/docs/html/about/versions/android-1.1.jd b/docs/html/about/versions/android-1.1.jd
index b61f186..b2a1615 100644
--- a/docs/html/about/versions/android-1.1.jd
+++ b/docs/html/about/versions/android-1.1.jd
@@ -1,4 +1,5 @@
 page.title=Android 1.1 Version Notes
+excludeFromSuggestions=true
 sdk.version=1.1_r1
 sys.date=February 2009
 @jd:body
diff --git a/docs/html/about/versions/android-1.5-highlights.jd b/docs/html/about/versions/android-1.5-highlights.jd
index ff64e8c..dd4d218 100644
--- a/docs/html/about/versions/android-1.5-highlights.jd
+++ b/docs/html/about/versions/android-1.5-highlights.jd
@@ -1,4 +1,5 @@
 page.title=Android 1.5 Platform Highlights
+excludeFromSuggestions=true
 @jd:body
 
 <p>
diff --git a/docs/html/about/versions/android-1.5.jd b/docs/html/about/versions/android-1.5.jd
index 78dcbd7..ca8771b 100644
--- a/docs/html/about/versions/android-1.5.jd
+++ b/docs/html/about/versions/android-1.5.jd
@@ -1,4 +1,5 @@
 page.title=Android 1.5 Platform
+excludeFromSuggestions=true
 sdk.platform.version=1.5
 sdk.platform.apiLevel=3
 sdk.platform.majorMinor=major
diff --git a/docs/html/about/versions/android-1.6-highlights.jd b/docs/html/about/versions/android-1.6-highlights.jd
index 0c56e8e..88c0f55 100644
--- a/docs/html/about/versions/android-1.6-highlights.jd
+++ b/docs/html/about/versions/android-1.6-highlights.jd
@@ -1,4 +1,5 @@
 page.title=Android 1.6 Platform Highlights
+excludeFromSuggestions=true
 sdk.date=September 2009
 
 @jd:body
diff --git a/docs/html/about/versions/android-1.6.jd b/docs/html/about/versions/android-1.6.jd
index 2a66cd3..313b77a 100644
--- a/docs/html/about/versions/android-1.6.jd
+++ b/docs/html/about/versions/android-1.6.jd
@@ -1,4 +1,5 @@
 page.title=Android 1.6 Platform
+excludeFromSuggestions=true
 sdk.platform.version=1.6
 sdk.platform.apiLevel=4
 sdk.platform.majorMinor=minor
diff --git a/docs/html/about/versions/android-2.0-highlights.jd b/docs/html/about/versions/android-2.0-highlights.jd
index bec49a3..3b23e4d 100644
--- a/docs/html/about/versions/android-2.0-highlights.jd
+++ b/docs/html/about/versions/android-2.0-highlights.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.0 Platform Highlights
+excludeFromSuggestions=true
 sdk.date=October 2009
 
 @jd:body
diff --git a/docs/html/about/versions/android-2.0.1.jd b/docs/html/about/versions/android-2.0.1.jd
index bcba717..ba00231 100644
--- a/docs/html/about/versions/android-2.0.1.jd
+++ b/docs/html/about/versions/android-2.0.1.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.0.1, Release 1
+excludeFromSuggestions=true
 sdk.platform.version=2.0.1
 sdk.platform.apiLevel=6
 sdk.platform.majorMinor=minor
diff --git a/docs/html/about/versions/android-2.0.jd b/docs/html/about/versions/android-2.0.jd
index 7a12e48..82bb78f 100644
--- a/docs/html/about/versions/android-2.0.jd
+++ b/docs/html/about/versions/android-2.0.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.0, Release 1
+excludeFromSuggestions=true
 sdk.platform.version=2.0
 sdk.platform.apiLevel=5
 sdk.platform.majorMinor=major
diff --git a/docs/html/about/versions/android-2.1.jd b/docs/html/about/versions/android-2.1.jd
index 3cb0708..2d5988a 100644
--- a/docs/html/about/versions/android-2.1.jd
+++ b/docs/html/about/versions/android-2.1.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.1 Platform
+excludeFromSuggestions=true
 sdk.platform.version=2.1
 sdk.platform.apiLevel=7
 sdk.platform.majorMinor=minor
diff --git a/docs/html/about/versions/android-2.2-highlights.jd b/docs/html/about/versions/android-2.2-highlights.jd
index 334d036..afbf26b 100644
--- a/docs/html/about/versions/android-2.2-highlights.jd
+++ b/docs/html/about/versions/android-2.2-highlights.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.2 Platform Highlights
+excludeFromSuggestions=true
 
 @jd:body
 
diff --git a/docs/html/about/versions/android-2.2.jd b/docs/html/about/versions/android-2.2.jd
index 64ddca4..bd0f071e 100644
--- a/docs/html/about/versions/android-2.2.jd
+++ b/docs/html/about/versions/android-2.2.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.2 APIs
+excludeFromSuggestions=true
 sdk.platform.version=2.2
 sdk.platform.apiLevel=8
 sdk.platform.majorMinor=minor
diff --git a/docs/html/about/versions/android-2.3.3.jd b/docs/html/about/versions/android-2.3.3.jd
index 3b40831..eec0735 100644
--- a/docs/html/about/versions/android-2.3.3.jd
+++ b/docs/html/about/versions/android-2.3.3.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.3.3 APIs
+excludeFromSuggestions=true
 sdk.platform.version=2.3.3
 sdk.platform.apiLevel=10
 
diff --git a/docs/html/about/versions/android-2.3.4.jd b/docs/html/about/versions/android-2.3.4.jd
index b80b4b2..963df9a 100644
--- a/docs/html/about/versions/android-2.3.4.jd
+++ b/docs/html/about/versions/android-2.3.4.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.3.4 APIs
+excludeFromSuggestions=true
 sdk.platform.version=2.3.4
 sdk.platform.apiLevel=10
 
diff --git a/docs/html/about/versions/android-2.3.jd b/docs/html/about/versions/android-2.3.jd
index 4feff51..4b8ef91 100644
--- a/docs/html/about/versions/android-2.3.jd
+++ b/docs/html/about/versions/android-2.3.jd
@@ -1,4 +1,5 @@
 page.title=Android 2.3 APIs
+excludeFromSuggestions=true
 sdk.platform.version=2.3
 sdk.platform.apiLevel=9
 
diff --git a/docs/html/about/versions/android-3.0.jd b/docs/html/about/versions/android-3.0.jd
index d0b41d3..f319fed 100644
--- a/docs/html/about/versions/android-3.0.jd
+++ b/docs/html/about/versions/android-3.0.jd
@@ -1,4 +1,5 @@
 page.title=Android 3.0 APIs
+excludeFromSuggestions=true
 sdk.platform.version=3.0
 sdk.platform.apiLevel=11
 @jd:body
diff --git a/docs/html/about/versions/android-3.1.jd b/docs/html/about/versions/android-3.1.jd
index 8681327..c22dfaa 100644
--- a/docs/html/about/versions/android-3.1.jd
+++ b/docs/html/about/versions/android-3.1.jd
@@ -1,4 +1,5 @@
 page.title=Android 3.1 APIs
+excludeFromSuggestions=true
 sdk.platform.version=3.1
 sdk.platform.apiLevel=12
 @jd:body
diff --git a/docs/html/about/versions/android-3.2.jd b/docs/html/about/versions/android-3.2.jd
index 17f4d85..ef95337 100644
--- a/docs/html/about/versions/android-3.2.jd
+++ b/docs/html/about/versions/android-3.2.jd
@@ -1,4 +1,5 @@
 page.title=Android 3.2 APIs
+excludeFromSuggestions=true
 sdk.platform.version=3.2
 sdk.platform.apiLevel=13
 @jd:body
diff --git a/docs/html/about/versions/android-4.0.3.jd b/docs/html/about/versions/android-4.0.3.jd
index dc69c99..5fa8547 100644
--- a/docs/html/about/versions/android-4.0.3.jd
+++ b/docs/html/about/versions/android-4.0.3.jd
@@ -1,4 +1,5 @@
 page.title=Android 4.0.3 APIs
+excludeFromSuggestions=true
 sdk.platform.version=4.0.3
 sdk.platform.apiLevel=15
 @jd:body
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index 868227a..1d81bc2 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -1,4 +1,5 @@
 page.title=Android 4.0 APIs
+excludeFromSuggestions=true
 sdk.platform.version=4.0
 sdk.platform.apiLevel=14
 @jd:body
diff --git a/docs/html/about/versions/android-4.1.jd b/docs/html/about/versions/android-4.1.jd
index 60ed7f0..060f0f4 100644
--- a/docs/html/about/versions/android-4.1.jd
+++ b/docs/html/about/versions/android-4.1.jd
@@ -1,4 +1,5 @@
 page.title=Android 4.1 APIs
+excludeFromSuggestions=true
 sdk.platform.version=4.1
 sdk.platform.apiLevel=16
 @jd:body
diff --git a/docs/html/about/versions/android-4.2.jd b/docs/html/about/versions/android-4.2.jd
index b02c1d1..73d51c5 100644
--- a/docs/html/about/versions/android-4.2.jd
+++ b/docs/html/about/versions/android-4.2.jd
@@ -1,4 +1,5 @@
 page.title=Android 4.2 APIs
+excludeFromSuggestions=true
 sdk.platform.version=4.2
 sdk.platform.apiLevel=17
 @jd:body
diff --git a/docs/html/distribute/googleplay/promote/brand.jd b/docs/html/distribute/googleplay/promote/brand.jd
index cea6d2c..265584f 100644
--- a/docs/html/distribute/googleplay/promote/brand.jd
+++ b/docs/html/distribute/googleplay/promote/brand.jd
@@ -172,5 +172,22 @@
     see <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to your products</a></p>
 
 
-<p>If you are not sure you meet these brand guidelines, <a href=
-            "http://services.google.com/permissions/application">please contact us</a>. </p>
+
+<h2 id="Questions">Questions</h2>
+
+<p>To view our full guidelines or for any further brand usage questions, please contact our
+Android Partner Marketing team:</p>
+<ul>
+  <li>For North and South America, please contact <a
+  href="mailto:android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
+  >android-brand-approvals@google.com</a></li>
+
+  <li>For Europe and Emerging Markets, please contact <a
+  href="mailto:emea-android-brand@google.com?Subject=Brand%20Approval%20Questions"
+  >emea-android-brand@google.com</a></li>
+
+  <li>For Asia and Pacific-America, please contact <a
+  href="mailto:apac-android-brand-approvals@google.com?Subject=Brand%20Approval%20Questions"
+  >apac-android-brand-approvals@google.com</a></li>
+</ul>
+
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index 5d34641..e96b204 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -1,4 +1,5 @@
 page.title=GCM: Getting Started
+page.tags="cloud","push","messaging"
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/google/play-services/auth.jd b/docs/html/google/play-services/auth.jd
index 8e11131..3ccc81a 100644
--- a/docs/html/google/play-services/auth.jd
+++ b/docs/html/google/play-services/auth.jd
@@ -1,4 +1,5 @@
 page.title=Authorization
+page.tags="AccountManager","oauth2"
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/google/play-services/maps.jd b/docs/html/google/play-services/maps.jd
index 5a4aaf4..965444a 100644
--- a/docs/html/google/play-services/maps.jd
+++ b/docs/html/google/play-services/maps.jd
@@ -1,4 +1,5 @@
 page.title=Google Maps Android API
+page.tags="mapview","location"
 header.hide=1
 
 @jd:body
diff --git a/docs/html/google/play-services/plus.jd b/docs/html/google/play-services/plus.jd
index de921be..e126dad 100644
--- a/docs/html/google/play-services/plus.jd
+++ b/docs/html/google/play-services/plus.jd
@@ -1,4 +1,5 @@
 page.title=Google+ Platform for Android
+page.tags="authentication","signin","social"
 header.hide=1
 
 @jd:body
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 0cf2df3..a960a18 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -1,4 +1,4 @@
-page.title=Setup
+page.title=Setup Google Play Services SDK
 @jd:body
 
 
diff --git a/docs/html/guide/appendix/app-intents.jd b/docs/html/guide/appendix/app-intents.jd
index 110196c..8898927 100644
--- a/docs/html/guide/appendix/app-intents.jd
+++ b/docs/html/guide/appendix/app-intents.jd
@@ -1,4 +1,5 @@
 page.title=Reference of Available Intents
+excludeFromSuggestions=true
 @jd:body
 
 <p>This document describes the default applications and settings that Google provides
diff --git a/docs/html/guide/appendix/g-app-intents.jd b/docs/html/guide/appendix/g-app-intents.jd
index 10ec01e..9ec72db 100644
--- a/docs/html/guide/appendix/g-app-intents.jd
+++ b/docs/html/guide/appendix/g-app-intents.jd
@@ -1,4 +1,5 @@
 page.title=Intents List: Invoking Google Applications on Android Devices
+excludeFromSuggestions=true
 @jd:body
 
 <div class="sidebox-wrapper">
diff --git a/docs/html/guide/appendix/glossary.jd b/docs/html/guide/appendix/glossary.jd
index 94cb0f0..af60eb7 100644
--- a/docs/html/guide/appendix/glossary.jd
+++ b/docs/html/guide/appendix/glossary.jd
@@ -1,4 +1,5 @@
 page.title=Glossary
+excludeFromSuggestions=true
 @jd:body
 
 <p>The list below defines some of the basic terminology of the Android platform. </p>
diff --git a/docs/html/guide/practices/compatibility.jd b/docs/html/guide/practices/compatibility.jd
index bc58403..9e3d461 100644
--- a/docs/html/guide/practices/compatibility.jd
+++ b/docs/html/guide/practices/compatibility.jd
@@ -1,4 +1,5 @@
 page.title=Android Compatibility
+excludeFromSuggestions=true
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/practices/index.jd b/docs/html/guide/practices/index.jd
index 48a849a..b61272b 100644
--- a/docs/html/guide/practices/index.jd
+++ b/docs/html/guide/practices/index.jd
@@ -1,4 +1,5 @@
 page.title=Best Practices
+excludeFromSuggestions=true
 page.landing=true
 page.landing.intro=Design and build apps the right way. Learn how to create apps that look great and perform well on as many devices as possible, from phones to tablets and more.  
 page.landing.image=
diff --git a/docs/html/guide/practices/optimizing-for-3.0.jd b/docs/html/guide/practices/optimizing-for-3.0.jd
index 0dd92d9..465a847 100644
--- a/docs/html/guide/practices/optimizing-for-3.0.jd
+++ b/docs/html/guide/practices/optimizing-for-3.0.jd
@@ -1,4 +1,5 @@
 page.title=Optimizing Apps for Android 3.0
+excludeFromSuggestions=true
 @jd:body
 
 
diff --git a/docs/html/guide/practices/screen-compat-mode.jd b/docs/html/guide/practices/screen-compat-mode.jd
index 7f10914..e3160c39 100644
--- a/docs/html/guide/practices/screen-compat-mode.jd
+++ b/docs/html/guide/practices/screen-compat-mode.jd
@@ -1,4 +1,5 @@
 page.title=Screen Compatibility Mode
+excludeFromSuggestions=true
 parent.title=Supporting Multiple Screens
 parent.link=screens_support.html
 
diff --git a/docs/html/guide/practices/screens-distribution.jd b/docs/html/guide/practices/screens-distribution.jd
index 29d2a8c..99eb04e 100644
--- a/docs/html/guide/practices/screens-distribution.jd
+++ b/docs/html/guide/practices/screens-distribution.jd
@@ -1,4 +1,5 @@
 page.title=Distributing to Specific Screens
+excludeFromSuggestions=true
 parent.title=Supporting Multiple Screens
 parent.link=screens_support.html
 
diff --git a/docs/html/guide/practices/screens-support-1.5.jd b/docs/html/guide/practices/screens-support-1.5.jd
index 15f0695..ad680d9 100644
--- a/docs/html/guide/practices/screens-support-1.5.jd
+++ b/docs/html/guide/practices/screens-support-1.5.jd
@@ -1,4 +1,5 @@
 page.title=Strategies for Android 1.5
+excludeFromSuggestions=true
 parent.title=Supporting Multiple Screens
 parent.link=screens_support.html
 
diff --git a/docs/html/guide/practices/seamlessness.jd b/docs/html/guide/practices/seamlessness.jd
index ec6b7fd..9679e2a 100644
--- a/docs/html/guide/practices/seamlessness.jd
+++ b/docs/html/guide/practices/seamlessness.jd
@@ -1,4 +1,5 @@
 page.title=Designing for Seamlessness
+excludeFromSuggestions=true
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
index cb2bc37..f6669e4 100644
--- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -1,4 +1,5 @@
 page.title=Activity and Task Design Guidelines
+excludeFromSuggestions=true
 parent.title=UI Guidelines
 parent.link=index.html
 @jd:body
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd
index 70ae862..0726660 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd
@@ -1,4 +1,5 @@
 page.title=Icon Design Guidelines
+excludeFromSuggestions=true
 parent.title=UI Guidelines
 parent.link=index.html
 @jd:body
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 9f835a7..831de45 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
@@ -1,4 +1,5 @@
 page.title=Action Bar Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
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 a2c1459..c958ed9 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_dialog.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_dialog.jd
@@ -1,4 +1,5 @@
 page.title=Dialog Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
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 4ec56b1..f47e186 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
@@ -1,4 +1,5 @@
 page.title=Launcher Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd b/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd
index 4529797..2df3a22 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd
@@ -1,4 +1,5 @@
 page.title=Launcher Icons (Archive)
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
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 38ceb85..29e1a93 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_list.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_list.jd
@@ -1,4 +1,5 @@
 page.title=List View Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd b/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd
index 24bce51..a5b3597 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd
@@ -1,4 +1,5 @@
 page.title=Menu Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
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 4cd4db3..4993adb 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
@@ -1,4 +1,5 @@
 page.title=Status Bar Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd b/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd
index 5338a4d..cbe6706 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd
@@ -1,4 +1,5 @@
 page.title=Tab Icons
+excludeFromSuggestions=true
 parent.title=Icon Design Guidelines
 parent.link=icon_design.html
 @jd:body
diff --git a/docs/html/guide/practices/ui_guidelines/index.jd b/docs/html/guide/practices/ui_guidelines/index.jd
index 7603f6b..91a0725 100644
--- a/docs/html/guide/practices/ui_guidelines/index.jd
+++ b/docs/html/guide/practices/ui_guidelines/index.jd
@@ -1,4 +1,5 @@
 page.title=User Interface Guidelines
+excludeFromSuggestions=true
 @jd:body
 
 
diff --git a/docs/html/guide/practices/ui_guidelines/menu_design.jd b/docs/html/guide/practices/ui_guidelines/menu_design.jd
index b4e2ea7..bf87bdd 100644
--- a/docs/html/guide/practices/ui_guidelines/menu_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/menu_design.jd
@@ -1,4 +1,5 @@
 page.title=Menu Design Guidelines
+excludeFromSuggestions=true
 parent.title=UI Guidelines
 parent.link=index.html
 @jd:body
diff --git a/docs/html/guide/practices/ui_guidelines/widget_design.jd b/docs/html/guide/practices/ui_guidelines/widget_design.jd
index a48d17d..cf2cd64 100644
--- a/docs/html/guide/practices/ui_guidelines/widget_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/widget_design.jd
@@ -1,4 +1,5 @@
 page.title=App Widget Design Guidelines
+excludeFromSuggestions=true
 parent.title=UI Guidelines
 parent.link=index.html
 @jd:body
diff --git a/docs/html/images/mediadrm_decryption_sequence.png b/docs/html/images/mediadrm_decryption_sequence.png
new file mode 100644
index 0000000..2bd95ea
--- /dev/null
+++ b/docs/html/images/mediadrm_decryption_sequence.png
Binary files differ
diff --git a/docs/html/images/mediadrm_overview.png b/docs/html/images/mediadrm_overview.png
new file mode 100644
index 0000000..dd66bce
--- /dev/null
+++ b/docs/html/images/mediadrm_overview.png
Binary files differ
diff --git a/docs/html/sdk/OLD_RELEASENOTES.jd b/docs/html/sdk/OLD_RELEASENOTES.jd
index 6865db2..b7fd12f 100644
--- a/docs/html/sdk/OLD_RELEASENOTES.jd
+++ b/docs/html/sdk/OLD_RELEASENOTES.jd
@@ -1,4 +1,5 @@
 page.title=Release Notes for Older SDK Versions
+excludeFromSuggestions=true
 @jd:body
 
 <div class="special">
diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd
index c7ece42..cbcbb12 100644
--- a/docs/html/sdk/RELEASENOTES.jd
+++ b/docs/html/sdk/RELEASENOTES.jd
@@ -1,4 +1,5 @@
 page.title=SDK Release Notes
+excludeFromSuggestions=true
 @jd:body
 
 <p>This document provides version-specific information about Android SDK
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 8005009..4329102 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -1,4 +1,5 @@
 page.title=Download an Archived Android SDK
+excludeFromSuggestions=true
 hide_license_footer=true
 
 @jd:body
diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd
index bb274b6..94baa92 100644
--- a/docs/html/sdk/older_releases.jd
+++ b/docs/html/sdk/older_releases.jd
@@ -1,4 +1,5 @@
 page.title=SDK Archives
+excludeFromSuggestions=true
 @jd:body
 
 <p>This page provides a full list of archived and obsolete SDK releases,
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 5d1990a..773328c 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -1711,6 +1711,8 @@
     }
 
     /**
+     * @hide
+     *
      * Interface to handle notification when new buffers are
      * available via USAGE_IO_INPUT.  An application will receive
      * one notification when a buffer is available.  Additional
@@ -1722,6 +1724,8 @@
     }
 
     /**
+     * @hide
+     *
      * Set a notification handler for USAGE_IO_INPUT
      *
      * @param callback instance of the IoInputNotifier class to be called
diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java
index decd0c7..730d973 100644
--- a/graphics/java/android/renderscript/FieldPacker.java
+++ b/graphics/java/android/renderscript/FieldPacker.java
@@ -23,6 +23,10 @@
  * Utility class for packing arguments and structures from Android system objects to
  * Renderscript objects.
  *
+ * This class is only intended to be used to support the
+ * reflected code generated by the RS tool chain.  It should not
+ * be called directly.
+ *
  **/
 public class FieldPacker {
     public FieldPacker(int len) {
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index b4ba943..f0579ca 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -166,6 +166,15 @@
         mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params);
     }
 
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param slot
+     * @param ain
+     * @param aout
+     * @param v
+     * @param sc
+     */
     protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
         if (ain == null && aout == null) {
             throw new RSIllegalArgumentException(
@@ -310,6 +319,12 @@
         mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims);
     }
 
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     * @param index
+     * @param v
+     */
     public void getVarV(int index, FieldPacker v) {
         mRS.nScriptGetVarV(getID(mRS), index, v.getData());
     }
@@ -332,6 +347,10 @@
     }
 
 
+    /**
+     * Only intended for use by generated reflected code.
+     *
+     */
     public static class FieldBase {
         protected Element mElement;
         protected Allocation mAllocation;
@@ -364,16 +383,29 @@
         }
     }
 
+
+    /**
+     * Class used to specify clipping for a kernel launch.
+     *
+     */
     public static final class LaunchOptions {
-        protected int xstart = 0;
-        protected int ystart = 0;
-        protected int xend = 0;
-        protected int yend = 0;
-        protected int zstart = 0;
-        protected int zend = 0;
+        private int xstart = 0;
+        private int ystart = 0;
+        private int xend = 0;
+        private int yend = 0;
+        private int zstart = 0;
+        private int zend = 0;
+        private int strategy;
 
-        protected int strategy;
-
+        /**
+         * Set the X range.  If the end value is set to 0 the X dimension is not
+         * clipped.
+         *
+         * @param xstartArg Must be >= 0
+         * @param xendArg Must be >= xstartArg
+         *
+         * @return LaunchOptions
+         */
         public LaunchOptions setX(int xstartArg, int xendArg) {
             if (xstartArg < 0 || xendArg <= xstartArg) {
                 throw new RSIllegalArgumentException("Invalid dimensions");
@@ -383,6 +415,15 @@
             return this;
         }
 
+        /**
+         * Set the Y range.  If the end value is set to 0 the Y dimension is not
+         * clipped.
+         *
+         * @param ystartArg Must be >= 0
+         * @param yendArg Must be >= ystartArg
+         *
+         * @return LaunchOptions
+         */
         public LaunchOptions setY(int ystartArg, int yendArg) {
             if (ystartArg < 0 || yendArg <= ystartArg) {
                 throw new RSIllegalArgumentException("Invalid dimensions");
@@ -392,6 +433,15 @@
             return this;
         }
 
+        /**
+         * Set the Z range.  If the end value is set to 0 the Z dimension is not
+         * clipped.
+         *
+         * @param zstartArg Must be >= 0
+         * @param zendArg Must be >= zstartArg
+         *
+         * @return LaunchOptions
+         */
         public LaunchOptions setZ(int zstartArg, int zendArg) {
             if (zstartArg < 0 || zendArg <= zstartArg) {
                 throw new RSIllegalArgumentException("Invalid dimensions");
@@ -402,21 +452,51 @@
         }
 
 
+        /**
+         * Returns the current X start
+         *
+         * @return int current value
+         */
         public int getXStart() {
             return xstart;
         }
+        /**
+         * Returns the current X end
+         *
+         * @return int current value
+         */
         public int getXEnd() {
             return xend;
         }
+        /**
+         * Returns the current Y start
+         *
+         * @return int current value
+         */
         public int getYStart() {
             return ystart;
         }
+        /**
+         * Returns the current Y end
+         *
+         * @return int current value
+         */
         public int getYEnd() {
             return yend;
         }
+        /**
+         * Returns the current Z start
+         *
+         * @return int current value
+         */
         public int getZStart() {
             return zstart;
         }
+        /**
+         * Returns the current Z end
+         *
+         * @return int current value
+         */
         public int getZEnd() {
             return zend;
         }
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
index 6975583..43d1eb6 100644
--- a/keystore/java/android/security/AndroidKeyPairGenerator.java
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -52,12 +52,12 @@
 public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
     private android.security.KeyStore mKeyStore;
 
-    private AndroidKeyPairGeneratorSpec mSpec;
+    private KeyPairGeneratorSpec mSpec;
 
     /**
      * Generate a KeyPair which is backed by the Android keystore service. You
      * must call {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
-     * with an {@link AndroidKeyPairGeneratorSpec} as the {@code params}
+     * with an {@link KeyPairGeneratorSpec} as the {@code params}
      * argument before calling this otherwise an {@code IllegalStateException}
      * will be thrown.
      * <p>
@@ -73,7 +73,7 @@
     public KeyPair generateKeyPair() {
         if (mKeyStore == null || mSpec == null) {
             throw new IllegalStateException(
-                    "Must call initialize with an AndroidKeyPairGeneratorSpec first");
+                    "Must call initialize with an android.security.KeyPairGeneratorSpec first");
         }
 
         if (((mSpec.getFlags() & KeyStore.FLAG_ENCRYPTED) != 0)
@@ -156,13 +156,13 @@
             throws InvalidAlgorithmParameterException {
         if (params == null) {
             throw new InvalidAlgorithmParameterException(
-                    "must supply params of type AndroidKeyPairGenericSpec");
-        } else if (!(params instanceof AndroidKeyPairGeneratorSpec)) {
+                    "must supply params of type android.security.KeyPairGeneratorSpec");
+        } else if (!(params instanceof KeyPairGeneratorSpec)) {
             throw new InvalidAlgorithmParameterException(
-                    "params must be of type AndroidKeyPairGeneratorSpec");
+                    "params must be of type android.security.KeyPairGeneratorSpec");
         }
 
-        AndroidKeyPairGeneratorSpec spec = (AndroidKeyPairGeneratorSpec) params;
+        KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params;
 
         mSpec = spec;
         mKeyStore = android.security.KeyStore.getInstance();
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index dcc9516..04ee8c4 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -209,7 +209,7 @@
     }
 
     private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain,
-            AndroidKeyStoreParameter params) throws KeyStoreException {
+            KeyStoreParameter params) throws KeyStoreException {
         byte[] keyBytes = null;
 
         final String pkeyAlias;
@@ -544,15 +544,16 @@
             return;
         }
 
-        if (param != null && !(param instanceof AndroidKeyStoreParameter)) {
-            throw new KeyStoreException("protParam should be AndroidKeyStoreParameter; was: "
+        if (param != null && !(param instanceof KeyStoreParameter)) {
+            throw new KeyStoreException(
+                    "protParam should be android.security.KeyStoreParameter; was: "
                     + param.getClass().getName());
         }
 
         if (entry instanceof PrivateKeyEntry) {
             PrivateKeyEntry prE = (PrivateKeyEntry) entry;
             setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(),
-                    (AndroidKeyStoreParameter) param);
+                    (KeyStoreParameter) param);
             return;
         }
 
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index 8ca301e..b17e450 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -24,7 +24,7 @@
  * @hide
  */
 public class AndroidKeyStoreProvider extends Provider {
-    public static final String PROVIDER_NAME = "AndroidKeyStoreProvider";
+    public static final String PROVIDER_NAME = "AndroidKeyStore";
 
     public AndroidKeyStoreProvider() {
         super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
@@ -33,6 +33,6 @@
         put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
 
         // java.security.KeyPairGenerator
-        put("KeyPairGenerator." + AndroidKeyStore.NAME, AndroidKeyPairGenerator.class.getName());
+        put("KeyPairGenerator.RSA", AndroidKeyPairGenerator.class.getName());
     }
 }
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
similarity index 89%
rename from keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
rename to keystore/java/android/security/KeyPairGeneratorSpec.java
index b126f036..59f89bc 100644
--- a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -29,9 +29,9 @@
 
 /**
  * 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
+ * {@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 AndroidKeyStore}
  * 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.
@@ -49,7 +49,7 @@
  * The self-signed X.509 certificate may be replaced at a later time by a
  * certificate signed by a real Certificate Authority.
  */
-public final class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
+public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
     private final String mKeystoreAlias;
 
     private final Context mContext;
@@ -91,9 +91,9 @@
      *            period
      * @throws IllegalArgumentException when any argument is {@code null} or
      *             {@code endDate} is before {@code startDate}.
-     * @hide should be built with AndroidKeyPairGeneratorSpecBuilder
+     * @hide should be built with KeyPairGeneratorSpecBuilder
      */
-    public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
+    public KeyPairGeneratorSpec(Context context, String keyStoreAlias,
             X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate,
             int flags) {
         if (context == null) {
@@ -184,7 +184,7 @@
     }
 
     /**
-     * Builder class for {@link AndroidKeyPairGeneratorSpec} objects.
+     * Builder class for {@link KeyPairGeneratorSpec} objects.
      * <p>
      * This will build a parameter spec for use with the <a href="{@docRoot}
      * guide/topics/security/keystore.html">Android KeyStore facility</a>.
@@ -198,14 +198,10 @@
      * Calendar end = new Calendar();
      * end.add(1, Calendar.YEAR);
      *
-     * AndroidKeyPairGeneratorSpec spec =
-     *         new AndroidKeyPairGeneratorSpec.Builder(mContext)
-     *                 .setAlias(&quot;myKey&quot;)
-     *                 .setSubject(new X500Principal(&quot;CN=myKey&quot;))
-     *                 .setSerial(BigInteger.valueOf(1337))
-     *                 .setStartDate(start.getTime())
-     *                 .setEndDate(end.getTime())
-     *                 .build();
+     * KeyPairGeneratorSpec spec =
+     *         new KeyPairGeneratorSpec.Builder(mContext).setAlias(&quot;myKey&quot;)
+     *                 .setSubject(new X500Principal(&quot;CN=myKey&quot;)).setSerial(BigInteger.valueOf(1337))
+     *                 .setStartDate(start.getTime()).setEndDate(end.getTime()).build();
      * </pre>
      */
     public final static class Builder {
@@ -309,13 +305,13 @@
         }
 
         /**
-         * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
+         * Builds the instance of the {@code KeyPairGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing
-         * @return built instance of {@code AndroidKeyPairGeneratorSpec}
+         * @return built instance of {@code KeyPairGeneratorSpec}
          */
-        public AndroidKeyPairGeneratorSpec build() {
-            return new AndroidKeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
+        public KeyPairGeneratorSpec build() {
+            return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
                     mSerialNumber, mStartDate, mEndDate, mFlags);
         }
     }
diff --git a/keystore/java/android/security/AndroidKeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
similarity index 72%
rename from keystore/java/android/security/AndroidKeyStoreParameter.java
rename to keystore/java/android/security/KeyStoreParameter.java
index 44f57c4..621a605 100644
--- a/keystore/java/android/security/AndroidKeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -17,7 +17,7 @@
 package android.security;
 
 import android.content.Context;
-import android.security.AndroidKeyPairGeneratorSpec.Builder;
+import android.security.KeyPairGeneratorSpec.Builder;
 
 import java.security.KeyPairGenerator;
 import java.security.PrivateKey;
@@ -26,9 +26,9 @@
 
 /**
  * This provides the optional parameters that can be specified for
- * {@code KeyStore} entries that work with <a href="{@docRoot}
- * guide/topics/security/keystore.html">Android KeyStore facility</a>. The
- * Android KeyStore facility is accessed through a
+ * {@code KeyStore} entries that work with
+ * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * facility</a>. The Android KeyStore facility is accessed through a
  * {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
  * 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.
@@ -39,15 +39,15 @@
  * {@code KeyStore}.
  * <p>
  * Keys may be generated using the {@link KeyPairGenerator} facility with a
- * {@link AndroidKeyPairGeneratorSpec} to specify the entry's {@code alias}. A
+ * {@link KeyPairGeneratorSpec} to specify the entry's {@code alias}. A
  * self-signed X.509 certificate will be attached to generated entries, but that
  * may be replaced at a later time by a certificate signed by a real Certificate
  * Authority.
  */
-public final class AndroidKeyStoreParameter implements ProtectionParameter {
+public final class KeyStoreParameter implements ProtectionParameter {
     private int mFlags;
 
-    private AndroidKeyStoreParameter(int flags) {
+    private KeyStoreParameter(int flags) {
         mFlags = flags;
     }
 
@@ -67,10 +67,10 @@
     }
 
     /**
-     * Builder class for {@link AndroidKeyStoreParameter} objects.
+     * Builder class for {@link KeyStoreParameter} objects.
      * <p>
-     * This will build protection parameters for use with the <a
-     * href="{@docRoot} guide/topics/security/keystore.html">Android KeyStore
+     * This will build protection parameters for use with the
+     * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
      * facility</a>.
      * <p>
      * This can be used to require that KeyStore entries be stored encrypted.
@@ -78,8 +78,9 @@
      * Example:
      *
      * <pre class="prettyprint">
-     * AndroidKeyStoreParameter params =
-     *         new AndroidKeyStoreParameter.Builder(mContext).setEncryptionRequired().build();
+     * KeyStoreParameter params = new KeyStoreParameter.Builder(mContext)
+     *         .setEncryptionRequired()
+     *         .build();
      * </pre>
      */
     public final static class Builder {
@@ -105,19 +106,23 @@
          * screen (e.g., PIN, password) before creating or using the generated
          * key is successful.
          */
-        public Builder setEncryptionRequired() {
-            mFlags |= KeyStore.FLAG_ENCRYPTED;
+        public Builder setEncryptionRequired(boolean required) {
+            if (required) {
+                mFlags |= KeyStore.FLAG_ENCRYPTED;
+            } else {
+                mFlags &= ~KeyStore.FLAG_ENCRYPTED;
+            }
             return this;
         }
 
         /**
-         * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
+         * Builds the instance of the {@code KeyPairGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing
-         * @return built instance of {@code AndroidKeyPairGeneratorSpec}
+         * @return built instance of {@code KeyPairGeneratorSpec}
          */
-        public AndroidKeyStoreParameter build() {
-            return new AndroidKeyStoreParameter(mFlags);
+        public KeyStoreParameter build() {
+            return new KeyStoreParameter(mFlags);
         }
     }
 }
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
index c5cf514..1582f74 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -65,7 +65,7 @@
 
         assertFalse(mAndroidKeyStore.isUnlocked());
 
-        mGenerator = java.security.KeyPairGenerator.getInstance("AndroidKeyStore");
+        mGenerator = java.security.KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
     }
 
     private void setupPassword() {
@@ -80,7 +80,7 @@
     public void testKeyPairGenerator_Initialize_Params_Encrypted_Success() throws Exception {
         setupPassword();
 
-        mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                 .setAlias(TEST_ALIAS_1)
                 .setSubject(TEST_DN_1)
                 .setSerialNumber(TEST_SERIAL_1)
@@ -116,7 +116,7 @@
         setupPassword();
 
         mGenerator.initialize(
-                new AndroidKeyPairGeneratorSpec.Builder(getContext())
+                new KeyPairGeneratorSpec.Builder(getContext())
                         .setAlias(TEST_ALIAS_1)
                         .setSubject(TEST_DN_1)
                         .setSerialNumber(TEST_SERIAL_1)
@@ -130,7 +130,7 @@
     public void testKeyPairGenerator_GenerateKeyPair_Encrypted_Success() throws Exception {
         setupPassword();
 
-        mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                 .setAlias(TEST_ALIAS_1)
                 .setSubject(TEST_DN_1)
                 .setSerialNumber(TEST_SERIAL_1)
@@ -146,7 +146,7 @@
     }
 
     public void testKeyPairGenerator_GenerateKeyPair_Unencrypted_Success() throws Exception {
-        mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                 .setAlias(TEST_ALIAS_1)
                 .setSubject(TEST_DN_1)
                 .setSerialNumber(TEST_SERIAL_1)
@@ -163,7 +163,7 @@
     public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception {
         // Generate the first key
         {
-            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                     .setAlias(TEST_ALIAS_1)
                     .setSubject(TEST_DN_1)
                     .setSerialNumber(TEST_SERIAL_1)
@@ -178,7 +178,7 @@
 
         // Replace the original key
         {
-            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                     .setAlias(TEST_ALIAS_2)
                     .setSubject(TEST_DN_2)
                     .setSerialNumber(TEST_SERIAL_2)
@@ -196,7 +196,7 @@
             throws Exception {
         // Generate the first key
         {
-            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                     .setAlias(TEST_ALIAS_1)
                     .setSubject(TEST_DN_1)
                     .setSerialNumber(TEST_SERIAL_1)
@@ -211,7 +211,7 @@
 
         // Attempt to replace previous key
         {
-            mGenerator.initialize(new AndroidKeyPairGeneratorSpec.Builder(getContext())
+            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
                     .setAlias(TEST_ALIAS_1)
                     .setSubject(TEST_DN_2)
                     .setSerialNumber(TEST_SERIAL_2)
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index 507d41c..8798fb5 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -1232,8 +1232,8 @@
 
         try {
             mKeyStore.setEntry(TEST_ALIAS_1, entry,
-                    new AndroidKeyStoreParameter.Builder(getContext())
-                    .setEncryptionRequired()
+                    new KeyStoreParameter.Builder(getContext())
+                    .setEncryptionRequired(true)
                     .build());
             fail("Shouldn't be able to insert encrypted entry when KeyStore uninitialized");
         } catch (KeyStoreException expected) {
@@ -1752,8 +1752,10 @@
             Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
 
             try {
-                mKeyStore.setEntry(TEST_ALIAS_1, entry, new AndroidKeyStoreParameter.Builder(
-                        getContext()).setEncryptionRequired().build());
+                mKeyStore.setEntry(TEST_ALIAS_1, entry,
+                        new KeyStoreParameter.Builder(getContext())
+                                .setEncryptionRequired(true)
+                                .build());
                 fail("Should not allow setting of Entry without unlocked keystore");
             } catch (KeyStoreException success) {
             }
@@ -1762,8 +1764,8 @@
             assertTrue(mAndroidKeyStore.isUnlocked());
 
             mKeyStore.setEntry(TEST_ALIAS_1, entry,
-                    new AndroidKeyStoreParameter.Builder(getContext())
-                            .setEncryptionRequired()
+                    new KeyStoreParameter.Builder(getContext())
+                            .setEncryptionRequired(true)
                             .build());
         }
     }
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
similarity index 83%
rename from keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
rename to keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
index 5d4ab9c..113d730 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
@@ -23,7 +23,7 @@
 
 import javax.security.auth.x500.X500Principal;
 
-public class AndroidKeyPairGeneratorSpecTest extends AndroidTestCase {
+public class KeyPairGeneratorSpecTest extends AndroidTestCase {
     private static final String TEST_ALIAS_1 = "test1";
 
     private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
@@ -39,8 +39,8 @@
     private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
 
     public void testConstructor_Success() throws Exception {
-        AndroidKeyPairGeneratorSpec spec =
-                new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
+        KeyPairGeneratorSpec spec =
+                new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
                         NOW, NOW_PLUS_10_YEARS, 0);
 
         assertEquals("Context should be the one specified", getContext(), spec.getContext());
@@ -55,7 +55,7 @@
     }
 
     public void testBuilder_Success() throws Exception {
-        AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(getContext())
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(getContext())
                 .setAlias(TEST_ALIAS_1)
                 .setSubject(TEST_DN_1)
                 .setSerialNumber(SERIAL_1)
@@ -79,7 +79,7 @@
 
     public void testConstructor_NullContext_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+            new KeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
                     NOW_PLUS_10_YEARS, 0);
             fail("Should throw IllegalArgumentException when context is null");
         } catch (IllegalArgumentException success) {
@@ -88,7 +88,7 @@
 
     public void testConstructor_NullKeystoreAlias_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW,
+            new KeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW,
                     NOW_PLUS_10_YEARS, 0);
             fail("Should throw IllegalArgumentException when keystoreAlias is null");
         } catch (IllegalArgumentException success) {
@@ -97,7 +97,7 @@
 
     public void testConstructor_NullSubjectDN_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW,
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW,
                     NOW_PLUS_10_YEARS, 0);
             fail("Should throw IllegalArgumentException when subjectDN is null");
         } catch (IllegalArgumentException success) {
@@ -106,7 +106,7 @@
 
     public void testConstructor_NullSerial_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW,
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW,
                     NOW_PLUS_10_YEARS, 0);
             fail("Should throw IllegalArgumentException when startDate is null");
         } catch (IllegalArgumentException success) {
@@ -115,7 +115,7 @@
 
     public void testConstructor_NullStartDate_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null,
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null,
                     NOW_PLUS_10_YEARS, 0);
             fail("Should throw IllegalArgumentException when startDate is null");
         } catch (IllegalArgumentException success) {
@@ -124,7 +124,7 @@
 
     public void testConstructor_NullEndDate_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
                     null, 0);
             fail("Should throw IllegalArgumentException when keystoreAlias is null");
         } catch (IllegalArgumentException success) {
@@ -133,7 +133,7 @@
 
     public void testConstructor_EndBeforeStart_Failure() throws Exception {
         try {
-            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
                     NOW_PLUS_10_YEARS, NOW, 0);
             fail("Should throw IllegalArgumentException when end is before start");
         } catch (IllegalArgumentException success) {
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index ad7edb1..c277c24 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -237,6 +237,8 @@
     }
 
     bool mergeAllowed() {
+        if (!state.mMatrix.isPureTranslate()) return false;
+
         // checks that we're unclipped, and srcover
         const Rect& opBounds = state.mBounds;
         return fabs(opBounds.getWidth() - mLocalBounds.getWidth()) < 0.1 &&
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index a718294..4adad05 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -45,6 +45,7 @@
     fbo = 0;
     stencil = NULL;
     debugDrawUpdate = false;
+    hasDrawnSinceUpdate = false;
     deferredList = NULL;
     Caches::getInstance().resourceCache.incrementRefcount(this);
 }
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 715dfa4..7186603 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -317,6 +317,7 @@
     DisplayList* displayList;
     Rect dirtyRect;
     bool debugDrawUpdate;
+    bool hasDrawnSinceUpdate;
 
 private:
     /**
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f81b4ff..6fc2771 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -550,6 +550,7 @@
         }
 
         layer->debugDrawUpdate = mCaches.debugLayersUpdates;
+        layer->hasDrawnSinceUpdate = false;
 
         return true;
     }
@@ -1088,11 +1089,28 @@
     }
 }
 
+/**
+ * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
+ * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
+ * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
+ * by saveLayer's restore
+ */
+#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
+        DRAW_COMMAND;                                                            \
+        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
+            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
+            DRAW_COMMAND;                                                        \
+            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
+        }                                                                        \
+    }
+
+#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
+
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
     if (layer->region.isRect()) {
         layer->setRegionAsRect();
 
-        composeLayerRect(layer, layer->regionRect);
+        DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
 
         layer->region.clear();
         return;
@@ -1162,14 +1180,16 @@
             numQuads++;
 
             if (numQuads >= REGION_MESH_QUAD_COUNT) {
-                glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+                DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+                                GL_UNSIGNED_SHORT, NULL));
                 numQuads = 0;
                 mesh = mCaches.getRegionMesh();
             }
         }
 
         if (numQuads > 0) {
-            glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+                            GL_UNSIGNED_SHORT, NULL));
         }
 
         finishDrawTexture();
@@ -3042,7 +3062,8 @@
         mDrawModifiers.mColorFilter = layer->getColorFilter();
 
         if (layer->region.isRect()) {
-            composeLayerRect(layer, layer->regionRect);
+            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                    composeLayerRect(layer, layer->regionRect));
         } else if (layer->mesh) {
             const float a = getLayerAlpha(layer);
             setupDraw();
@@ -3068,8 +3089,9 @@
             }
             setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
 
-            glDrawElements(GL_TRIANGLES, layer->meshElementCount,
-                    GL_UNSIGNED_SHORT, layer->meshIndices);
+            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                    glDrawElements(GL_TRIANGLES, layer->meshElementCount,
+                            GL_UNSIGNED_SHORT, layer->meshIndices));
 
             finishDrawTexture();
 
@@ -3086,6 +3108,7 @@
                     0x7f00ff00, SkXfermode::kSrcOver_Mode);
         }
     }
+    layer->hasDrawnSinceUpdate = true;
 
     if (transform && !transform->isIdentity()) {
         restore();
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 917a47d..56e98e4 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -1205,6 +1206,11 @@
      * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
      * <p>Even if a SCO connection is established, the following restrictions apply on audio
      * output streams so that they can be routed to SCO headset:
+     * <p>NOTE: up to and including API version
+     * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
+     * voice call to the bluetooth headset.
+     * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
+     * connection is established.
      * <ul>
      *   <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
      *   <li> the format must be mono </li>
@@ -1226,7 +1232,7 @@
     public void startBluetoothSco(){
         IAudioService service = getService();
         try {
-            service.startBluetoothSco(mICallBack);
+            service.startBluetoothSco(mICallBack, mContext.getApplicationInfo().targetSdkVersion);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in startBluetoothSco", e);
         }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 637ac85..0df4f82 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -48,6 +48,7 @@
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -369,6 +370,14 @@
     // waiting for headset service to connect
     private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
 
+    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
+    // originated from an app targeting an API version before JB MR2 and raw audio after that.
+    private int mScoAudioMode;
+    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
+    private static final int SCO_MODE_VIRTUAL_CALL = 0;
+    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
+    private static final int SCO_MODE_RAW = 1;
+
     // Current connection state indicated by bluetooth headset
     private int mScoConnectionState;
 
@@ -1910,7 +1919,7 @@
     }
 
     /** @see AudioManager#startBluetoothSco() */
-    public void startBluetoothSco(IBinder cb){
+    public void startBluetoothSco(IBinder cb, int targetSdkVersion){
         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
                 !mBootCompleted) {
             return;
@@ -1922,7 +1931,7 @@
         // The caller identity must be cleared after getScoClient() because it is needed if a new
         // client is created.
         final long ident = Binder.clearCallingIdentity();
-        client.incCount();
+        client.incCount(targetSdkVersion);
         Binder.restoreCallingIdentity(ident);
     }
 
@@ -1968,9 +1977,9 @@
             }
         }
 
-        public void incCount() {
+        public void incCount(int targetSdkVersion) {
             synchronized(mScoClients) {
-                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED);
+                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
                 if (mStartcount == 0) {
                     try {
                         mCb.linkToDeath(this, 0);
@@ -1996,7 +2005,7 @@
                             Log.w(TAG, "decCount() going to 0 but not registered to binder");
                         }
                     }
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
                 }
             }
         }
@@ -2012,7 +2021,7 @@
                 }
                 mStartcount = 0;
                 if (stopSco) {
-                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
                 }
             }
         }
@@ -2040,7 +2049,7 @@
             }
         }
 
-        private void requestScoState(int state) {
+        private void requestScoState(int state, int targetSdkVersion) {
             checkScoAudioState();
             if (totalCount() == 0) {
                 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
@@ -2055,8 +2064,18 @@
                                 (mScoAudioState == SCO_STATE_INACTIVE ||
                                  mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
                             if (mScoAudioState == SCO_STATE_INACTIVE) {
+                                mScoAudioMode =
+                                        (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
+                                                SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                                    if (mBluetoothHeadset.connectAudio()) {
+                                    boolean status;
+                                    if (mScoAudioMode == SCO_MODE_RAW) {
+                                        status = mBluetoothHeadset.connectAudio();
+                                    } else {
+                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                                                            mBluetoothHeadsetDevice);
+                                    }
+                                    if (status) {
                                         mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
                                     } else {
                                         broadcastScoConnectionState(
@@ -2078,7 +2097,14 @@
                                mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
                     if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
                         if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
-                            if (!mBluetoothHeadset.disconnectAudio()) {
+                            boolean status;
+                            if (mScoAudioMode == SCO_MODE_RAW) {
+                                status = mBluetoothHeadset.disconnectAudio();
+                            } else {
+                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                            }
+                            if (!status) {
                                 mScoAudioState = SCO_STATE_INACTIVE;
                                 broadcastScoConnectionState(
                                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -2251,10 +2277,20 @@
                             switch (mScoAudioState) {
                             case SCO_STATE_ACTIVATE_REQ:
                                 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                status = mBluetoothHeadset.connectAudio();
+                                if (mScoAudioMode == SCO_MODE_RAW) {
+                                    status = mBluetoothHeadset.connectAudio();
+                                } else {
+                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                                }
                                 break;
                             case SCO_STATE_DEACTIVATE_REQ:
-                                status = mBluetoothHeadset.disconnectAudio();
+                                if (mScoAudioMode == SCO_MODE_RAW) {
+                                    status = mBluetoothHeadset.disconnectAudio();
+                                } else {
+                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
+                                                                        mBluetoothHeadsetDevice);
+                                }
                                 break;
                             case SCO_STATE_DEACTIVATE_EXT_REQ:
                                 status = mBluetoothHeadset.stopVoiceRecognition(
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 13f6c02..0d285fc 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -179,7 +179,7 @@
            int  getRemoteStreamVolume();
     oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
 
-    void startBluetoothSco(IBinder cb);
+    void startBluetoothSco(IBinder cb, int targetSdkVersion);
     void stopBluetoothSco(IBinder cb);
 
     void forceVolumeControlStream(int streamType, IBinder cb);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 1501c79..df87db3 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -44,7 +44,16 @@
         return MediaCodecList.getSupportedTypes(mIndex);
     }
 
+    /**
+     * Encapsulates the capabilities of a given codec component,
+     * i.e. what profile/level combinations it supports and what colorspaces
+     * it is capable of providing the decoded data in.
+     */
     public static final class CodecCapabilities {
+        // Enumerates supported profile/level combinations as defined
+        // by the type of encoded data. These combinations impose restrictions
+        // on video resolution, bitrate... and limit the available encoder tools
+        // such as B-frame support, arithmetic coding...
         public CodecProfileLevel[] profileLevels;
 
         // from OMX_COLOR_FORMATTYPE
@@ -219,6 +228,11 @@
         public int level;
     };
 
+    /**
+     * Enumerates the capabilities of the codec component. Since a single
+     * component can support data of a variety of types, the type has to be
+     * specified to yield a meaningful result.
+     */
     public final CodecCapabilities getCapabilitiesForType(
             String type) {
         return MediaCodecList.getCodecCapabilities(mIndex, type);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6872278..a58fa51 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -29,25 +29,69 @@
 import android.util.Log;
 
 /**
- * MediaDrm can be used in conjunction with {@link android.media.MediaCrypto}
- * to obtain keys for decrypting protected media data.
- *
- * Crypto schemes are assigned 16 byte UUIDs,
- * the method {@link #isCryptoSchemeSupported} can be used to query if a given
- * scheme is supported on the device.
- *
+ * MediaDrm can be used to obtain keys for decrypting protected media streams, in
+ * conjunction with {@link android.media.MediaCrypto}.  The MediaDrm APIs
+ * are designed to support the ISO/IEC 23001-7: Common Encryption standard, but
+ * may also be used to implement other encryption schemes.
+ * <p>
+ * Encrypted content is prepared using an encryption server and stored in a content
+ * library. The encrypted content is streamed or downloaded from the content library to
+ * client devices via content servers.  Licenses to view the content are obtained from
+ * a License Server.
+ * <p>
+ * <p><img src="../../../images/mediadrm_overview.png"
+ *      alt="MediaDrm Overview diagram"
+ *      border="0" /></p>
+ * <p>
+ * Keys are requested from the license server using a key request. The key
+ * response is delivered to the client app, which provides the response to the
+ * MediaDrm API.
+ * <p>
+ * A Provisioning server may be required to distribute device-unique credentials to
+ * the devices.
+ * <p>
+ * Enforcing requirements related to the number of devices that may play content
+ * simultaneously can be performed either through key renewal or using the secure
+ * stop methods.
+ * <p>
+ * The following sequence diagram shows the interactions between the objects
+ * involved while playing back encrypted content:
+ * <p>
+ * <p><img src="../../../images/mediadrm_decryption_sequence.png"
+ *         alt="MediaDrm Overview diagram"
+ *         border="0" /></p>
+ * <p>
+ * The app first constructs {@link android.media.MediaExtractor} and
+ * {@link android.media.MediaCodec} objects. It accesses the DRM-scheme-identifying UUID,
+ * typically from metadata in the content, and uses this UUID to construct an instance
+ * of a MediaDrm object that is able to support the DRM scheme required by the content.
+ * Crypto schemes are assigned 16 byte UUIDs.  The method {@link #isCryptoSchemeSupported}
+ * can be used to query if a given scheme is supported on the device.
+ * <p>
+ * The app calls {@link #openSession} to generate a sessionId that will uniquely identify
+ * the session in subsequent interactions. The app next uses the MediaDrm object to
+ * obtain a key request message and send it to the license server, then provide
+ * the server's response to the MediaDrm object.
+ * <p>
+ * Once the app has a sessionId, it can construct a MediaCrypto object from the UUID and
+ * sessionId.  The MediaCrypto object is registered with the MediaCodec in the
+ * {@link MediaCodec.#configure} method to enable the codec to decrypt content.
+ * <p>
+ * When the app has constructed {@link android.media.MediaExtractor},
+ * {@link android.media.MediaCodec} and {@link android.media.MediaCrypto} objects,
+ * it proceeds to pull samples from the extractor and queue them into the decoder.  For
+ * encrypted content, the samples returned from the extractor remain encrypted, they
+ * are only decrypted when the samples are delivered to the decoder.
+ * <p>
  * <a name="Callbacks"></a>
  * <h3>Callbacks</h3>
- * <p>Applications may want to register for informational events in order
- * to be informed of some internal state update during playback or streaming.
+ * <p>Applications should register for informational events in order
+ * to be informed of key state updates during playback or streaming.
  * Registration for these events is done via a call to
- * {@link #setOnEventListener(OnInfoListener)}setOnInfoListener,
- * In order to receive the respective callback
- * associated with this listener, applications are required to create
+ * {@link #setOnEventListener}. In order to receive the respective
+ * callback associated with this listener, applications are required to create
  * MediaDrm objects on a thread with its own Looper running (main UI
  * thread by default has a Looper running).
- *
- * @hide -- don't expose yet
  */
 public final class MediaDrm {
 
@@ -116,7 +160,7 @@
 
     /**
      * Interface definition for a callback to be invoked when a drm event
-     * occurs.
+     * occurs
      */
     public interface OnEventListener
     {
@@ -132,10 +176,30 @@
         void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
     }
 
-    public static final int MEDIA_DRM_EVENT_PROVISION_REQUIRED = 1;
-    public static final int MEDIA_DRM_EVENT_KEY_REQUIRED = 2;
-    public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
-    public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
+    /**
+     * This event type indicates that the app needs to request a certificate from
+     * the provisioning server.  The request message data is obtained using
+     * {@link #getProvisionRequest}
+     */
+    public static final int EVENT_PROVISION_REQUIRED = 1;
+
+    /**
+     * This event type indicates that the app needs to request keys from a license
+     * server.  The request message data is obtained using {@link #getKeyRequest}.
+     */
+    public static final int EVENT_KEY_REQUIRED = 2;
+
+    /**
+     * This event type indicates that the licensed usage duration for keys in a session
+     * has expired.  The keys are no longer valid.
+     */
+    public static final int EVENT_KEY_EXPIRED = 3;
+
+    /**
+     * This event may indicate some specific vendor-defined condition, see your
+     * DRM provider documentation for details
+     */
+    public static final int EVENT_VENDOR_DEFINED = 4;
 
     private static final int DRM_EVENT = 200;
 
@@ -183,7 +247,7 @@
     }
 
     /*
-     * Called from native code when an interesting event happens.  This method
+     * This method is called from native code when an event occurs.  This method
      * just uses the EventHandler system to post the event back to the main app thread.
      * We use a weak reference to the original MediaPlayer object so that the native
      * code is safe from the object disappearing from underneath it.  (This is
@@ -203,89 +267,117 @@
     }
 
     /**
-     *  Open a new session with the MediaDrm object.  A session ID is returned.
+     * Open a new session with the MediaDrm object.  A session ID is returned.
      */
-    public native byte[] openSession() throws MediaDrmException;
+    public native byte[] openSession();
 
     /**
-     *  Close a session on the MediaDrm object that was previously opened
-     *  with {@link #openSession}.
+     * Close a session on the MediaDrm object that was previously opened
+     * with {@link #openSession}.
      */
-    public native void closeSession(byte[] sessionId) throws MediaDrmException;
+    public native void closeSession(byte[] sessionId);
 
-    public static final int MEDIA_DRM_KEY_TYPE_STREAMING = 1;
-    public static final int MEDIA_DRM_KEY_TYPE_OFFLINE = 2;
-    public static final int MEDIA_DRM_KEY_TYPE_RELEASE = 3;
+    /**
+     * This key request type species that the keys will be for online use, they will
+     * not be saved to the device for subsequent use when the device is not connected
+     * to a network.
+     */
+    public static final int KEY_TYPE_STREAMING = 1;
 
-    public final class KeyRequest {
-        public KeyRequest() {}
-        public byte[] data;
-        public String defaultUrl;
+    /**
+     * This key request type specifies that the keys will be for offline use, they
+     * will be saved to the device for use when the device is not connected to a network.
+     */
+    public static final int KEY_TYPE_OFFLINE = 2;
+
+    /**
+     * This key request type specifies that previously saved offline keys should be released.
+     */
+    public static final int KEY_TYPE_RELEASE = 3;
+
+    /**
+     * Contains the opaque data an app uses to request keys from a license server
+     */
+    public final static class KeyRequest {
+        KeyRequest() {}
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() { return mData; }
+
+        /**
+         * Get the default URL to use when sending the key request message to a
+         * server, if known.  The app may prefer to use a different license
+         * server URL from other sources.
+         */
+        public String getDefaultUrl() { return mDefaultUrl; }
+
+        private byte[] mData;
+        private String mDefaultUrl;
     };
 
     /**
      * A key request/response exchange occurs between the app and a license server
      * to obtain or release keys used to decrypt encrypted content.
+     * <p>
      * getKeyRequest() is used to obtain an opaque key request byte array that is
      * delivered to the license server.  The opaque key request byte array is returned
      * in KeyRequest.data.  The recommended URL to deliver the key request to is
      * returned in KeyRequest.defaultUrl.
-     *
+     * <p>
      * After the app has received the key request response from the server,
      * it should deliver to the response to the DRM engine plugin using the method
      * {@link #provideKeyResponse}.
      *
      * @param scope may be a sessionId or a keySetId, depending on the specified keyType.
-     * When the keyType is MEDIA_DRM_KEY_TYPE_STREAMING or MEDIA_DRM_KEY_TYPE_OFFLINE,
+     * When the keyType is KEY_TYPE_STREAMING or KEY_TYPE_OFFLINE,
      * scope should be set to the sessionId the keys will be provided to.  When the keyType
-     * is MEDIA_DRM_KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
+     * is KEY_TYPE_RELEASE, scope should be set to the keySetId of the keys
      * being released. Releasing keys from a device invalidates them for all sessions.
      * @param init container-specific data, its meaning is interpreted based on the
      * mime type provided in the mimeType parameter.  It could contain, for example,
      * the content ID, key ID or other data obtained from the content metadata that is
      * required in generating the key request. init may be null when keyType is
-     * MEDIA_DRM_KEY_TYPE_RELEASE.
+     * KEY_TYPE_RELEASE.
      * @param mimeType identifies the mime type of the content
      * @param keyType specifes the type of the request. The request may be to acquire
      * keys for streaming or offline content, or to release previously acquired
      * keys, which are identified by a keySetId.
-
      * @param optionalParameters are included in the key request message to
      * allow a client application to provide additional message parameters to the server.
      */
     public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
                                            String mimeType, int keyType,
-                                           HashMap<String, String> optionalParameters)
-        throws MediaDrmException;
+                                           HashMap<String, String> optionalParameters);
+
 
     /**
      * A key response is received from the license server by the app, then it is
      * provided to the DRM engine plugin using provideKeyResponse. The byte array
      * returned is a keySetId that can be used to later restore the keys to a new
-     * session with the method {@link restoreKeys}, enabling offline key use.
+     * session with the method {@link #restoreKeys}, enabling offline key use.
      *
      * @param sessionId the session ID for the DRM session
      * @param response the byte array response from the server
      */
-    public native byte[] provideKeyResponse(byte[] sessionId, byte[] response)
-        throws MediaDrmException;
+    public native byte[] provideKeyResponse(byte[] sessionId, byte[] response);
 
     /**
      * Restore persisted offline keys into a new session.  keySetId identifies the
-     * keys to load, obtained from a prior call to {@link provideKeyResponse}.
+     * keys to load, obtained from a prior call to {@link #provideKeyResponse}.
      *
      * @param sessionId the session ID for the DRM session
      * @param keySetId identifies the saved key set to restore
      */
-    public native void restoreKeys(byte[] sessionId, byte[] keySetId)
-        throws MediaDrmException;
+    public native void restoreKeys(byte[] sessionId, byte[] keySetId);
 
     /**
      * Remove the current keys from a session.
      *
      * @param sessionId the session ID for the DRM session
      */
-    public native void removeKeys(byte[] sessionId) throws MediaDrmException;
+    public native void removeKeys(byte[] sessionId);
 
     /**
      * Request an informative description of the key status for the session.  The status is
@@ -296,25 +388,41 @@
      *
      * @param sessionId the session ID for the DRM session
      */
-    public native HashMap<String, String> queryKeyStatus(byte[] sessionId)
-        throws MediaDrmException;
+    public native HashMap<String, String> queryKeyStatus(byte[] sessionId);
 
-    public final class ProvisionRequest {
-        public ProvisionRequest() {}
-        public byte[] data;
-        public String defaultUrl;
+    /**
+     * Contains the opaque data an app uses to request a certificate from a provisioning
+     * server
+     */
+    public final static class ProvisionRequest {
+        ProvisionRequest() {}
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() { return mData; }
+
+        /**
+         * Get the default URL to use when sending the provision request
+         * message to a server, if known. The app may prefer to use a different
+         * provisioning server URL obtained from other sources.
+         */
+        public String getDefaultUrl() { return mDefaultUrl; }
+
+        private byte[] mData;
+        private String mDefaultUrl;
     }
 
     /**
      * A provision request/response exchange occurs between the app and a provisioning
      * server to retrieve a device certificate.  If provisionining is required, the
-     * MEDIA_DRM_EVENT_PROVISION_REQUIRED event will be sent to the event handler.
+     * EVENT_PROVISION_REQUIRED event will be sent to the event handler.
      * getProvisionRequest is used to obtain the opaque provision request byte array that
      * should be delivered to the provisioning server. The provision request byte array
      * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
      * request to is returned in ProvisionRequest.defaultUrl.
      */
-    public native ProvisionRequest getProvisionRequest() throws MediaDrmException;
+    public native ProvisionRequest getProvisionRequest();
 
     /**
      * After a provision response is received by the app, it is provided to the DRM
@@ -323,92 +431,91 @@
      * @param response the opaque provisioning response byte array to provide to the
      * DRM engine plugin.
      */
-    public native void provideProvisionResponse(byte[] response)
-        throws MediaDrmException;
+    public native void provideProvisionResponse(byte[] response);
 
     /**
-     * A means of enforcing the contractual requirement for a concurrent stream limit
-     * per subscriber across devices is provided via SecureStop.  SecureStop is a means
-     * of securely monitoring the lifetime of sessions. Since playback on a device can
-     * be interrupted due to reboot, power failure, etc. a means of persisting the
-     * lifetime information on the device is needed.
-     *
-     * A signed version of the sessionID is written to persistent storage on the device
-     * when each MediaCrypto object is created. The sessionID is signed by the device
-     * private key to prevent tampering.
-     *
+     * A means of enforcing limits on the number of concurrent streams per subscriber
+     * across devices is provided via SecureStop. This is achieved by securely
+     * monitoring the lifetime of sessions.
+     * <p>
+     * Information from the server related to the current playback session is written
+     * to persistent storage on the device when each MediaCrypto object is created.
+     * <p>
      * In the normal case, playback will be completed, the session destroyed and the
-     * Secure Stops will be queried. The App queries secure stops and forwards the
+     * Secure Stops will be queried. The app queries secure stops and forwards the
      * secure stop message to the server which verifies the signature and notifies the
      * server side database that the session destruction has been confirmed. The persisted
      * record on the client is only removed after positive confirmation that the server
      * received the message using releaseSecureStops().
      */
-    public native List<byte[]> getSecureStops() throws MediaDrmException;
+    public native List<byte[]> getSecureStops();
 
 
     /**
      * Process the SecureStop server response message ssRelease.  After authenticating
-     * the message, remove the SecureStops identiied in the response.
+     * the message, remove the SecureStops identified in the response.
      *
      * @param ssRelease the server response indicating which secure stops to release
      */
-    public native void releaseSecureStops(byte[] ssRelease)
-        throws MediaDrmException;
+    public native void releaseSecureStops(byte[] ssRelease);
 
 
     /**
-     * Read a DRM engine plugin property value, given the property name string.  There are
-     * several forms of property access functions, depending on the data type returned.
-     *
+     * String property name: identifies the maker of the DRM engine plugin
+     */
+    public static final String PROPERTY_VENDOR = "vendor";
+
+    /**
+     * String property name: identifies the version of the DRM engine plugin
+     */
+    public static final String PROPERTY_VERSION = "version";
+
+    /**
+     * String property name: describes the DRM engine plugin
+     */
+    public static final String PROPERTY_DESCRIPTION = "description";
+
+    /**
+     * String property name: a comma-separated list of cipher and mac algorithms
+     * supported by CryptoSession.  The list may be empty if the DRM engine
+     * plugin does not support CryptoSession operations.
+     */
+    public static final String PROPERTY_ALGORITHMS = "algorithms";
+
+    /**
+     * Read a DRM engine plugin String property value, given the property name string.
+     * <p>
      * Standard fields names are:
-     *   vendor         String - identifies the maker of the DRM engine plugin
-     *   version        String - identifies the version of the DRM engine plugin
-     *   description    String - describes the DRM engine plugin
-     *   deviceUniqueId byte[] - The device unique identifier is established during device
-     *                           provisioning and provides a means of uniquely identifying
-     *                           each device
-     *   algorithms     String - a comma-separate list of cipher and mac algorithms supported
-     *                           by CryptoSession.  The list may be empty if the DRM engine
-     *                           plugin does not support CryptoSession operations.
+     * {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
+     * {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
      */
-    public native String getPropertyString(String propertyName)
-        throws MediaDrmException;
+    public native String getPropertyString(String propertyName);
 
-    public native byte[] getPropertyByteArray(String propertyName)
-        throws MediaDrmException;
 
     /**
-     * Write a DRM engine plugin property value.  There are several forms of
-     * property setting functions, depending on the data type being set.
+     * Byte array property name: the device unique identifier is established during
+     * device provisioning and provides a means of uniquely identifying each device.
      */
-    public native void setPropertyString(String propertyName, String value)
-        throws MediaDrmException;
-
-    public native void setPropertyByteArray(String propertyName, byte[] value)
-        throws MediaDrmException;
+    public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
 
     /**
-     * In addition to supporting decryption of DASH Common Encrypted Media, the
-     * MediaDrm APIs provide the ability to securely deliver session keys from
-     * an operator's session key server to a client device, based on the factory-installed
-     * root of trust, and provide the ability to do encrypt, decrypt, sign and verify
-     * with the session key on arbitrary user data.
-     *
-     * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
-     * based on the established session keys.  These keys are exchanged using the
-     * getKeyRequest/provideKeyResponse methods.
-     *
-     * Applications of this capability could include securing various types of
-     * purchased or private content, such as applications, books and other media,
-     * photos or media delivery protocols.
-     *
-     * Operators can create session key servers that are functionally similar to a
-     * license key server, except that instead of receiving license key requests and
-     * providing encrypted content keys which are used specifically to decrypt A/V media
-     * content, the session key server receives session key requests and provides
-     * encrypted session keys which can be used for general purpose crypto operations.
+     * Read a DRM engine plugin byte array property value, given the property name string.
+     * <p>
+     * Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
      */
+    public native byte[] getPropertyByteArray(String propertyName);
+
+
+    /**
+     * Set a DRM engine plugin String property value.
+     */
+    public native void setPropertyString(String propertyName, String value);
+
+    /**
+     * Set a DRM engine plugin byte array property value.
+     */
+    public native void setPropertyByteArray(String propertyName, byte[] value);
+
 
     private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
                                                               String algorithm);
@@ -429,61 +536,112 @@
                                                      byte[] keyId, byte[] message,
                                                      byte[] signature);
 
+    /**
+     * In addition to supporting decryption of DASH Common Encrypted Media, the
+     * MediaDrm APIs provide the ability to securely deliver session keys from
+     * an operator's session key server to a client device, based on the factory-installed
+     * root of trust, and then perform encrypt, decrypt, sign and verify operations
+     * with the session key on arbitrary user data.
+     * <p>
+     * The CryptoSession class implements generic encrypt/decrypt/sign/verify methods
+     * based on the established session keys.  These keys are exchanged using the
+     * getKeyRequest/provideKeyResponse methods.
+     * <p>
+     * Applications of this capability could include securing various types of
+     * purchased or private content, such as applications, books and other media,
+     * photos or media delivery protocols.
+     * <p>
+     * Operators can create session key servers that are functionally similar to a
+     * license key server, except that instead of receiving license key requests and
+     * providing encrypted content keys which are used specifically to decrypt A/V media
+     * content, the session key server receives session key requests and provides
+     * encrypted session keys which can be used for general purpose crypto operations.
+     * <p>
+     * A CryptoSession is obtained using {@link #getCryptoSession}
+     */
     public final class CryptoSession {
         private MediaDrm mDrm;
         private byte[] mSessionId;
 
-        /**
-         * Construct a CryptoSession which can be used to encrypt, decrypt,
-         * sign and verify messages or data using the session keys established
-         * for the session using methods {@link getKeyRequest} and
-         * {@link provideKeyResponse} using a session key server.
-         *
-         * @param sessionId the session ID for the session containing keys
-         * to be used for encrypt, decrypt, sign and/or verify
-         *
-         * @param cipherAlgorithm the algorithm to use for encryption and
-         * decryption ciphers. The algorithm string conforms to JCA Standard
-         * Names for Cipher Transforms and is case insensitive.  For example
-         * "AES/CBC/PKCS5Padding".
-         *
-         * @param macAlgorithm the algorithm to use for sign and verify
-         * The algorithm string conforms to JCA Standard Names for Mac
-         * Algorithms and is case insensitive.  For example "HmacSHA256".
-         *
-         * The list of supported algorithms for a DRM engine plugin can be obtained
-         * using the method {@link getPropertyString("algorithms")}
-         */
-
-        public CryptoSession(MediaDrm drm, byte[] sessionId,
-                             String cipherAlgorithm, String macAlgorithm)
-            throws MediaDrmException {
+        CryptoSession(MediaDrm drm, byte[] sessionId,
+                      String cipherAlgorithm, String macAlgorithm)
+        {
             mSessionId = sessionId;
             mDrm = drm;
             setCipherAlgorithmNative(drm, sessionId, cipherAlgorithm);
             setMacAlgorithmNative(drm, sessionId, macAlgorithm);
         }
 
+        /**
+         * Encrypt data using the CryptoSession's cipher algorithm
+         *
+         * @param keyid specifies which key to use
+         * @param input the data to encrypt
+         * @param iv the initialization vector to use for the cipher
+         */
         public byte[] encrypt(byte[] keyid, byte[] input, byte[] iv) {
             return encryptNative(mDrm, mSessionId, keyid, input, iv);
         }
 
+        /**
+         * Decrypt data using the CryptoSessions's cipher algorithm
+         *
+         * @param keyid specifies which key to use
+         * @param input the data to encrypt
+         * @param iv the initialization vector to use for the cipher
+         */
         public byte[] decrypt(byte[] keyid, byte[] input, byte[] iv) {
             return decryptNative(mDrm, mSessionId, keyid, input, iv);
         }
 
+        /**
+         * Sign data using the CryptoSessions's mac algorithm.
+         *
+         * @param keyid specifies which key to use
+         * @param message the data for which a signature is to be computed
+         */
         public byte[] sign(byte[] keyid, byte[] message) {
             return signNative(mDrm, mSessionId, keyid, message);
         }
+
+        /**
+         * Verify a signature using the CryptoSessions's mac algorithm. Return true
+         * if the signatures match, false if they do no.
+         *
+         * @param keyid specifies which key to use
+         * @param message the data to verify
+         * @param signature the reference signature which will be compared with the
+         *        computed signature
+         */
         public boolean verify(byte[] keyid, byte[] message, byte[] signature) {
             return verifyNative(mDrm, mSessionId, keyid, message, signature);
         }
     };
 
+    /**
+     * Obtain a CryptoSession object which can be used to encrypt, decrypt,
+     * sign and verify messages or data using the session keys established
+     * for the session using methods {@link #getKeyRequest} and
+     * {@link #provideKeyResponse} using a session key server.
+     *
+     * @param sessionId the session ID for the session containing keys
+     * to be used for encrypt, decrypt, sign and/or verify
+     * @param cipherAlgorithm the algorithm to use for encryption and
+     * decryption ciphers. The algorithm string conforms to JCA Standard
+     * Names for Cipher Transforms and is case insensitive.  For example
+     * "AES/CBC/NoPadding".
+     * @param macAlgorithm the algorithm to use for sign and verify
+     * The algorithm string conforms to JCA Standard Names for Mac
+     * Algorithms and is case insensitive.  For example "HmacSHA256".
+     * <p>
+     * The list of supported algorithms for a DRM engine plugin can be obtained
+     * using the method {@link #getPropertyString} with the property name
+     * "algorithms".
+     */
     public CryptoSession getCryptoSession(byte[] sessionId,
                                           String cipherAlgorithm,
                                           String macAlgorithm)
-        throws MediaDrmException {
+    {
         return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
     }
 
@@ -495,8 +653,7 @@
     public native final void release();
     private static native final void native_init();
 
-    private native final void native_setup(Object mediadrm_this, byte[] uuid)
-        throws MediaDrmException;
+    private native final void native_setup(Object mediadrm_this, byte[] uuid);
 
     private native final void native_finalize();
 
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
index 6f81f90..d6f5ff4 100644
--- a/media/java/android/media/MediaDrmException.java
+++ b/media/java/android/media/MediaDrmException.java
@@ -19,8 +19,6 @@
 /**
  * Exception thrown if MediaDrm object could not be instantiated for
  * whatever reason.
- *
- * @hide -- don't expose yet
  */
 public final class MediaDrmException extends Exception {
     public MediaDrmException(String detailMessage) {
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 4a5e82e..f77ddc4 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -65,6 +65,7 @@
 public class RemoteControlClient
 {
     private final static String TAG = "RemoteControlClient";
+    private final static boolean DEBUG = false;
 
     /**
      * Playback state of a RemoteControlClient which is stopped.
@@ -219,7 +220,7 @@
     public final static int PLAYBACKINFO_USES_STREAM = 5;
 
     //==========================================
-    // Public flags for the supported transport control capabililities
+    // Public flags for the supported transport control capabilities
     /**
      * Flag indicating a RemoteControlClient makes use of the "previous" media key.
      *
@@ -642,6 +643,57 @@
                 sendPlaybackState_syncCacheLock();
                 // update AudioService
                 sendAudioServiceNewPlaybackState_syncCacheLock();
+
+                // handle automatic playback position refreshes
+                if (mEventHandler == null) {
+                    return;
+                }
+                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
+                if (timeInMs == PLAYBACK_POSITION_INVALID) {
+                    // this playback state refresh has no known playback position, it's no use
+                    // trying to see if there is any drift at this point
+                    // (this also bypasses this mechanism for older apps that use the old
+                    //  setPlaybackState(int) API)
+                    return;
+                }
+                if (playbackPositionShouldMove(mPlaybackState)) {
+                    // playback position moving, schedule next position drift check
+                    mEventHandler.sendMessageDelayed(
+                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
+                            getCheckPeriodFromSpeed(playbackSpeed));
+                }
+            }
+        }
+    }
+
+    private void onPositionDriftCheck() {
+        if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
+        synchronized(mCacheLock) {
+            if ((mEventHandler == null) || (mPositionProvider == null)) {
+                return;
+            }
+            if ((mPlaybackPositionMs == PLAYBACK_POSITION_INVALID) || (mPlaybackSpeed == 0.0f)) {
+                if (DEBUG) { Log.d(TAG, " no position or 0 speed, no check needed"); }
+                return;
+            }
+            long estPos = mPlaybackPositionMs + (long)
+                    ((SystemClock.elapsedRealtime() - mPlaybackStateChangeTimeMs) / mPlaybackSpeed);
+            long actPos = mPositionProvider.onGetPlaybackPosition();
+            if (actPos >= 0) {
+                if (Math.abs(estPos - actPos) > POSITION_DRIFT_MAX_MS) {
+                    // drift happened, report the new position
+                    if (DEBUG) { Log.w(TAG, " drift detected: actual=" +actPos +"  est=" +estPos); }
+                    setPlaybackState(mPlaybackState, actPos, mPlaybackSpeed);
+                } else {
+                    if (DEBUG) { Log.d(TAG, " no drift: actual=" + actPos +"  est=" + estPos); }
+                    // no drift, schedule the next drift check
+                    mEventHandler.sendMessageDelayed(
+                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
+                            getCheckPeriodFromSpeed(mPlaybackSpeed));
+                }
+            } else {
+                // invalid position (negative value), can't check for drift
+                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
             }
         }
     }
@@ -746,6 +798,14 @@
                 // tell RCDs that this RCC's playback position capabilities have changed
                 sendTransportControlInfo_syncCacheLock();
             }
+            if ((mPositionProvider != null) && (mEventHandler != null)
+                    && playbackPositionShouldMove(mPlaybackState)) {
+                // playback position is already moving, but now we have a position provider,
+                // so schedule a drift check right now
+                mEventHandler.sendMessageDelayed(
+                        mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
+                        0 /*check now*/);
+            }
         }
     }
 
@@ -999,7 +1059,7 @@
             if (mEventHandler != null) {
                 // signal new client
                 mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
-                mEventHandler.dispatchMessage(
+                mEventHandler.sendMessage(
                         mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
                                 /*arg1*/ generationId, /*arg2, ignored*/ 0));
                 // send the information
@@ -1007,12 +1067,12 @@
                 mEventHandler.removeMessages(MSG_REQUEST_METADATA);
                 mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
                 mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
-                mEventHandler.dispatchMessage(
+                mEventHandler.sendMessage(
                         mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
-                mEventHandler.dispatchMessage(
+                mEventHandler.sendMessage(
                         mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
             }
         }
 
@@ -1020,7 +1080,7 @@
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
             }
         }
@@ -1028,7 +1088,7 @@
         public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
             // only post messages, we can't block here
             if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_PLUG_DISPLAY, w, h, rcd));
             }
         }
@@ -1036,7 +1096,7 @@
         public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
             // only post messages, we can't block here
             if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_UNPLUG_DISPLAY, rcd));
             }
         }
@@ -1044,7 +1104,7 @@
         public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
             // only post messages, we can't block here
             if ((mEventHandler != null) && (rcd != null)) {
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
             }
         }
@@ -1053,7 +1113,7 @@
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 mEventHandler.removeMessages(MSG_SEEK_TO);
-                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
+                mEventHandler.sendMessage(mEventHandler.obtainMessage(
                         MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
                         new Long(timeMs)));
             }
@@ -1099,6 +1159,7 @@
     private final static int MSG_UNPLUG_DISPLAY = 8;
     private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
     private final static int MSG_SEEK_TO = 10;
+    private final static int MSG_POSITION_DRIFT_CHECK = 11;
 
     private class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1145,6 +1206,10 @@
                     break;
                 case MSG_SEEK_TO:
                     onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
+                    break;
+                case MSG_POSITION_DRIFT_CHECK:
+                    onPositionDriftCheck();
+                    break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
             }
@@ -1439,4 +1504,57 @@
             return false;
         }
     }
+
+    /**
+     * Returns whether, for the given playback state, the playback position is expected to
+     * be changing.
+     * @param playstate the playback state to evaluate
+     * @return true during any form of playback, false if it's not playing anything while in this
+     *     playback state
+     */
+    private static boolean playbackPositionShouldMove(int playstate) {
+        switch(playstate) {
+            case PLAYSTATE_STOPPED:
+            case PLAYSTATE_PAUSED:
+            case PLAYSTATE_BUFFERING:
+            case PLAYSTATE_ERROR:
+            case PLAYSTATE_SKIPPING_FORWARDS:
+            case PLAYSTATE_SKIPPING_BACKWARDS:
+                return false;
+            case PLAYSTATE_PLAYING:
+            case PLAYSTATE_FAST_FORWARDING:
+            case PLAYSTATE_REWINDING:
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * Period for playback position drift checks, 15s when playing at 1x or slower.
+     */
+    private final static long POSITION_REFRESH_PERIOD_PLAYING_MS = 15000;
+    /**
+     * Minimum period for playback position drift checks, never more often when every 2s, when
+     * fast forwarding or rewinding.
+     */
+    private final static long POSITION_REFRESH_PERIOD_MIN_MS = 2000;
+    /**
+     * The value above which the difference between client-reported playback position and
+     * estimated position is considered a drift.
+     */
+    private final static long POSITION_DRIFT_MAX_MS = 500;
+    /**
+     * Compute the period at which the estimated playback position should be compared against the
+     * actual playback position. Is a funciton of playback speed.
+     * @param speed 1.0f is normal playback speed
+     * @return the period in ms
+     */
+    private static long getCheckPeriodFromSpeed(float speed) {
+        if (Math.abs(speed) <= 1.0f) {
+            return POSITION_REFRESH_PERIOD_PLAYING_MS;
+        } else {
+            return Math.max((long)(POSITION_REFRESH_PERIOD_PLAYING_MS / Math.abs(speed)),
+                    POSITION_REFRESH_PERIOD_MIN_MS);
+        }
+    }
 }
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c32ba9d..d1b499e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -30,6 +30,7 @@
 #include <media/IDrm.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -191,10 +192,62 @@
 static bool throwExceptionAsNecessary(
         JNIEnv *env, status_t err, const char *msg = NULL) {
 
+    const char *drmMessage = NULL;
+
+    switch(err) {
+    case ERROR_DRM_UNKNOWN:
+        drmMessage = "General DRM error";
+        break;
+    case ERROR_DRM_NO_LICENSE:
+        drmMessage = "No license";
+        break;
+    case ERROR_DRM_LICENSE_EXPIRED:
+        drmMessage = "License expired";
+        break;
+    case ERROR_DRM_SESSION_NOT_OPENED:
+        drmMessage = "Session not opened";
+        break;
+    case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
+        drmMessage = "Not initialized";
+        break;
+    case ERROR_DRM_DECRYPT:
+        drmMessage = "Decrypt error";
+        break;
+    case ERROR_DRM_CANNOT_HANDLE:
+        drmMessage = "Unsupported scheme or data format";
+        break;
+    case ERROR_DRM_TAMPER_DETECTED:
+        drmMessage = "Invalid state";
+        break;
+    case ERROR_DRM_NOT_PROVISIONED:
+        drmMessage = "Not provisioned";
+        break;
+    case ERROR_DRM_DEVICE_REVOKED:
+        drmMessage = "Device revoked";
+        break;
+    default:
+        break;
+    }
+
+    String8 vendorMessage;
+    if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
+        vendorMessage.format("DRM vendor-defined error: %d", err);
+        drmMessage = vendorMessage.string();
+    }
+
     if (err == BAD_VALUE) {
         jniThrowException(env, "java/lang/IllegalArgumentException", msg);
         return true;
     } else if (err != OK) {
+        String8 errbuf;
+        if (drmMessage != NULL) {
+            if (msg == NULL) {
+                msg = drmMessage;
+            } else {
+                errbuf.format("%s: %s", msg, drmMessage);
+                msg = errbuf.string();
+            }
+        }
         jniThrowException(env, "java/lang/IllegalStateException", msg);
         return true;
     }
@@ -458,22 +511,22 @@
                          "(Ljava/lang/Object;IILjava/lang/Object;)V");
 
     jfieldID field;
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
     gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_REQUIRED", "I");
     gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_KEY_EXPIRED", "I");
     gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "EVENT_VENDOR_DEFINED", "I");
     gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
 
     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
-    GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
-    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+    GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
+    GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
 
     FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
-    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
-    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+    GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
+    GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
 
     FIND_CLASS(clazz, "java/util/ArrayList");
     GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index ab7ceb6..5a2e261 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -18,6 +18,7 @@
 
 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;
@@ -29,13 +30,10 @@
 import javax.microedition.khronos.opengles.GL10;
 
 import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Trace;
+import android.content.pm.ConfigurationInfo;
+import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Choreographer;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
@@ -166,26 +164,11 @@
     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.
@@ -258,7 +241,13 @@
         // underlying surface is created and destroyed
         SurfaceHolder holder = getHolder();
         holder.addCallback(this);
-        mUserRenderMode = RENDERMODE_CONTINUOUSLY;
+        // 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);
     }
 
     /**
@@ -357,16 +346,15 @@
     public void setRenderer(Renderer renderer) {
         checkRenderThreadState();
         if (mEGLConfigChooser == null) {
-            mEGLConfigChooser = new SimpleEGLConfigChooser(true, mEGLContextClientVersion);
+            mEGLConfigChooser = new SimpleEGLConfigChooser(true);
         }
         if (mEGLContextFactory == null) {
-            mEGLContextFactory = new DefaultContextFactory(mEGLContextClientVersion);
+            mEGLContextFactory = new DefaultContextFactory();
         }
         if (mEGLWindowSurfaceFactory == null) {
             mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
         }
         mRenderer = renderer;
-
         mGLThread = new GLThread(mThisWeakRef);
         mGLThread.start();
     }
@@ -432,7 +420,7 @@
      * @param needDepth
      */
     public void setEGLConfigChooser(boolean needDepth) {
-        setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth, mEGLContextClientVersion));
+        setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
     }
 
     /**
@@ -451,7 +439,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, mEGLContextClientVersion));
+                blueSize, alphaSize, depthSize, stencilSize));
     }
 
     /**
@@ -478,13 +466,6 @@
      * 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) {
@@ -509,14 +490,6 @@
      * @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);
     }
 
@@ -528,7 +501,7 @@
      * @see #RENDERMODE_WHEN_DIRTY
      */
     public int getRenderMode() {
-        return mUserRenderMode;
+        return mGLThread.getRenderMode();
     }
 
     /**
@@ -609,8 +582,14 @@
             Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
         }
         if (mDetached && (mRenderer != null)) {
+            int renderMode = RENDERMODE_CONTINUOUSLY;
+            if (mGLThread != null) {
+                renderMode = mGLThread.getRenderMode();
+            }
             mGLThread = new GLThread(mThisWeakRef);
-            mGLThread.setRenderMode(mUserRenderMode);
+            if (renderMode != RENDERMODE_CONTINUOUSLY) {
+                mGLThread.setRenderMode(renderMode);
+            }
             mGLThread.start();
         }
         mDetached = false;
@@ -782,15 +761,11 @@
         void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
     }
 
-    private static class DefaultContextFactory implements EGLContextFactory {
-        private final int mEGLContextClientVersion;
-
-        public DefaultContextFactory(int version) {
-            mEGLContextClientVersion = version;
-        }
+    private class DefaultContextFactory implements EGLContextFactory {
+        private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
 
         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
-            int[] attrib_list = {EGL14.EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
                     EGL10.EGL_NONE };
 
             return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
@@ -800,9 +775,9 @@
         public void destroyContext(EGL10 egl, EGLDisplay display,
                 EGLContext context) {
             if (!egl.eglDestroyContext(display, context)) {
-                Log.e(TAG, "display:" + display + " context: " + context);
+                Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
                 if (LOG_THREADS) {
-                    Log.d(TAG, "tid=" + Thread.currentThread().getId());
+                    Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId());
                 }
                 EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
             }
@@ -832,8 +807,8 @@
             try {
                 result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
             } catch (IllegalArgumentException e) {
-                // This exception indicates that the surfaceflinger surface
-                // is not valid. This can happen if the surfaceflinger surface has
+                // This exception indicates that the surface flinger surface
+                // is not valid. This can happen if the surface flinger 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,
@@ -869,11 +844,10 @@
         EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
     }
 
-    private static abstract class BaseConfigChooser
+    private abstract class BaseConfigChooser
             implements EGLConfigChooser {
-
-        public BaseConfigChooser(int[] configSpec, int version) {
-            mConfigSpec = filterConfigSpec(configSpec, version);
+        public BaseConfigChooser(int[] configSpec) {
+            mConfigSpec = filterConfigSpec(configSpec);
         }
 
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
@@ -907,8 +881,8 @@
 
         protected int[] mConfigSpec;
 
-        private int[] filterConfigSpec(int[] configSpec, int version) {
-            if (version != 2) {
+        private int[] filterConfigSpec(int[] configSpec) {
+            if (mEGLContextClientVersion != 2) {
                 return configSpec;
             }
             /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
@@ -918,7 +892,7 @@
             int[] newConfigSpec = new int[len + 2];
             System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
             newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
-            newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT;
+            newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
             newConfigSpec[len+1] = EGL10.EGL_NONE;
             return newConfigSpec;
         }
@@ -928,9 +902,9 @@
      * Choose a configuration with exactly the specified r,g,b,a sizes,
      * and at least the specified depth and stencil sizes.
      */
-    private static class ComponentSizeChooser extends BaseConfigChooser {
+    private class ComponentSizeChooser extends BaseConfigChooser {
         public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
-                int alphaSize, int depthSize, int stencilSize, int version) {
+                int alphaSize, int depthSize, int stencilSize) {
             super(new int[] {
                     EGL10.EGL_RED_SIZE, redSize,
                     EGL10.EGL_GREEN_SIZE, greenSize,
@@ -938,7 +912,7 @@
                     EGL10.EGL_ALPHA_SIZE, alphaSize,
                     EGL10.EGL_DEPTH_SIZE, depthSize,
                     EGL10.EGL_STENCIL_SIZE, stencilSize,
-                    EGL10.EGL_NONE}, version);
+                    EGL10.EGL_NONE});
             mValue = new int[1];
             mRedSize = redSize;
             mGreenSize = greenSize;
@@ -946,7 +920,7 @@
             mAlphaSize = alphaSize;
             mDepthSize = depthSize;
             mStencilSize = stencilSize;
-        }
+       }
 
         @Override
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
@@ -957,10 +931,14 @@
                 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;
@@ -987,16 +965,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 static class SimpleEGLConfigChooser extends ComponentSizeChooser {
-        public SimpleEGLConfigChooser(boolean withDepthBuffer, int version) {
-            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0, version);
+    private class SimpleEGLConfigChooser extends ComponentSizeChooser {
+        public SimpleEGLConfigChooser(boolean withDepthBuffer) {
+            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
         }
     }
 
@@ -1013,9 +991,9 @@
          * Initialize EGL for a given configuration spec.
          * @param configSpec
          */
-        public void initialize() {
+        public void start() {
             if (LOG_EGL) {
-                Log.d(TAG, "initialize() tid=" + Thread.currentThread().getId());
+                Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
             }
             /*
              * Get an EGL instance
@@ -1056,7 +1034,7 @@
                 throwEglException("createContext");
             }
             if (LOG_EGL) {
-                Log.d(TAG, "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
+                Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
             }
 
             mEglSurface = null;
@@ -1070,7 +1048,7 @@
          */
         public boolean createSurface() {
             if (LOG_EGL) {
-                Log.d(TAG, "createSurface()  tid=" + Thread.currentThread().getId());
+                Log.w("EglHelper", "createSurface()  tid=" + Thread.currentThread().getId());
             }
             /*
              * Check preconditions.
@@ -1105,7 +1083,7 @@
             if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
                 int error = mEgl.eglGetError();
                 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
-                    Log.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
                 }
                 return false;
             }
@@ -1119,9 +1097,8 @@
                  * Could not make the context current, probably because the underlying
                  * SurfaceView surface has been destroyed.
                  */
-                logEglErrorAsWarning(TAG, "eglMakeCurrent", mEgl.eglGetError());
-                // we fall-through to "true" here because we do have a
-                // valid EGLSurface at this point.
+                logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
+                return false;
             }
 
             return true;
@@ -1131,7 +1108,8 @@
          * Create a GL object for the current EGL context.
          * @return
          */
-        public GL createGL() {
+        GL createGL() {
+
             GL gl = mEglContext.getGL();
             GLSurfaceView view = mGLSurfaceViewWeakRef.get();
             if (view != null) {
@@ -1167,7 +1145,7 @@
 
         public void destroySurface() {
             if (LOG_EGL) {
-                Log.d(TAG, "destroySurface()  tid=" + Thread.currentThread().getId());
+                Log.w("EglHelper", "destroySurface()  tid=" + Thread.currentThread().getId());
             }
             destroySurfaceImp();
         }
@@ -1185,9 +1163,9 @@
             }
         }
 
-        public void terminate() {
+        public void finish() {
             if (LOG_EGL) {
-                Log.d(TAG, "terminate() tid=" + Thread.currentThread().getId());
+                Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId());
             }
             if (mEglContext != null) {
                 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
@@ -1209,7 +1187,7 @@
         public static void throwEglException(String function, int error) {
             String message = formatEglError(function, error);
             if (LOG_THREADS) {
-                Log.e(TAG, "throwEglException tid=" + Thread.currentThread().getId() + " "
+                Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " "
                         + message);
             }
             throw new RuntimeException(message);
@@ -1229,411 +1207,584 @@
         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 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 ***");
-            }
+    static class GLThread extends Thread {
+        GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
+            super();
             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 {
-                super.run();
+                guardedRun();
+            } catch (InterruptedException e) {
+                // fall thru and exit normally
             } finally {
-                // by definition the GLThread is not running anymore here
-                stopEglContext();
-                stopEglSurface();
+                sGLThreadManager.threadExiting(this);
             }
         }
 
-        // only call from the GLThread
-        private void stopEglSurface() {
+        /*
+         * This private method should only be called inside a
+         * synchronized(sGLThreadManager) block.
+         */
+        private void stopEglSurfaceLocked() {
             if (mHaveEglSurface) {
-                if (LOG_SURFACE) {
-                    Log.d(TAG, "releasing EGL surface because paused tid=" + getId());
-                }
                 mHaveEglSurface = false;
                 mEglHelper.destroySurface();
             }
         }
 
-        // only call from the GLThread
-        private void stopEglContext() {
+        /*
+         * This private method should only be called inside a
+         * synchronized(sGLThreadManager) block.
+         */
+        private void stopEglContextLocked() {
             if (mHaveEglContext) {
-                mEglHelper.terminate();
+                mEglHelper.finish();
                 mHaveEglContext = false;
-                if (LOG_SURFACE) {
-                    Log.d(TAG, "releasing EGL context because paused tid=" + getId());
-                }
+                sGLThreadManager.releaseEglContextLocked(this);
             }
         }
+        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;
 
-        private void updateState() {
-            final boolean wasAbleToDraw = isAbleToDraw();
-            if (!isReadyToDraw()) {
-                return;
-            }
+                while (true) {
+                    synchronized (sGLThreadManager) {
+                        while (true) {
+                            if (mShouldExit) {
+                                return;
+                            }
 
-            if (!mHaveEglSurface || mSizeChanged) {
-                // create EGL context if needed
-                boolean reportSurfaceCreated = false;
-                if (!mHaveEglContext) {
-                    mEglHelper.initialize();
-                    mHaveEglContext = true;
-                    reportSurfaceCreated = true;
-                }
+                            if (! mEventQueue.isEmpty()) {
+                                event = mEventQueue.remove(0);
+                                break;
+                            }
 
-                // get the GL interface for the active EGLContext
-                mGLContext = (GL10)mEglHelper.createGL();
+                            // 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());
+                                }
+                            }
 
-                // create EGL Surface
-                mHaveEglSurface = mEglHelper.createSurface();
-                mEglSurfaceIsBad = !mHaveEglSurface;
-                mSizeChanged = false;
+                            // 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;
+                            }
 
-                // notify use of surface size change
-                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
-                if (view != null) {
-                    if (reportSurfaceCreated) {
-                        if (LOG_RENDERER) {
-                            Log.d(TAG, "onSurfaceCreated");
+                            // 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
+                                    + " mFinishedCreatingEglSurface: " + mFinishedCreatingEglSurface
+                                    + " mPaused: " + mPaused
+                                    + " mHasSurface: " + mHasSurface
+                                    + " mSurfaceIsBad: " + mSurfaceIsBad
+                                    + " mWaitingForSurface: " + mWaitingForSurface
+                                    + " mWidth: " + mWidth
+                                    + " mHeight: " + mHeight
+                                    + " mRequestRender: " + mRequestRender
+                                    + " mRenderMode: " + mRenderMode);
+                            }
+                            sGLThreadManager.wait();
                         }
-                        view.mRenderer.onSurfaceCreated(mGLContext, mEglHelper.mEglConfig);
+                    } // end of synchronized(sGLThreadManager)
+
+                    if (event != null) {
+                        event.run();
+                        event = null;
+                        continue;
                     }
 
-                    if (LOG_RENDERER) {
-                        Log.d(TAG, "onSurfaceChanged(" + mWidth + ", " + mHeight + ")");
+                    if (createEglSurface) {
+                        if (LOG_SURFACE) {
+                            Log.w("GLThread", "egl createSurface");
+                        }
+                        if (mEglHelper.createSurface()) {
+                            synchronized(sGLThreadManager) {
+                                mFinishedCreatingEglSurface = true;
+                                sGLThreadManager.notifyAll();
+                            }
+                        } else {
+                            synchronized(sGLThreadManager) {
+                                mFinishedCreatingEglSurface = true;
+                                mSurfaceIsBad = true;
+                                sGLThreadManager.notifyAll();
+                            }
+                            continue;
+                        }
+                        createEglSurface = false;
                     }
-                    view.mRenderer.onSurfaceChanged(mGLContext, mWidth, mHeight);
-                }
-            }
 
-            // see if we should kick the rendering loop
-            if (!wasAbleToDraw && isAbleToDraw()) {
-                // we're now able to draw
-                if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
-                    requestRender();
-                }
-            }
+                    if (createGlInterface) {
+                        gl = (GL10) mEglHelper.createGL();
 
-            // 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);
-            }
-        }
+                        sGLThreadManager.checkGLDriver(gl);
+                        createGlInterface = false;
+                    }
 
-        private void executeDraw() {
-            if (TRACE_ENABLED) {
-                Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "executeDraw");
-            }
+                    if (createEglContext) {
+                        if (LOG_RENDERER) {
+                            Log.w("GLThread", "onSurfaceCreated");
+                        }
+                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+                        if (view != null) {
+                            view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
+                        }
+                        createEglContext = false;
+                    }
 
-            if (isAbleToDraw()) {
-                if (mRenderMode == RENDERMODE_CONTINUOUSLY) {
-                    requestRender();
-                }
+                    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_DRAW_FRAME) {
-                    Log.d(TAG, "onDrawFrame tid=" + getId());
-                }
-
-                GLSurfaceView view = mGLSurfaceViewWeakRef.get();
-                if (view != null) {
-                    view.mRenderer.onDrawFrame(mGLContext);
+                    if (LOG_RENDERER_DRAW_FRAME) {
+                        Log.w("GLThread", "onDrawFrame tid=" + getId());
+                    }
+                    {
+                        GLSurfaceView view = mGLSurfaceViewWeakRef.get();
+                        if (view != null) {
+                            view.mRenderer.onDrawFrame(gl);
+                        }
+                    }
                     int swapError = mEglHelper.swap();
                     switch (swapError) {
                         case EGL10.EGL_SUCCESS:
                             break;
                         case EGL11.EGL_CONTEXT_LOST:
                             if (LOG_SURFACE) {
-                                Log.d(TAG, "egl context lost tid=" + getId());
+                                Log.i("GLThread", "egl context lost tid=" + getId());
                             }
-                            stopEglSurface();
-                            stopEglContext();
+                            lostEglContext = true;
                             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(TAG, "eglSwapBuffers", swapError);
-                            mEglSurfaceIsBad = true;
+                            EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
+
+                            synchronized(sGLThreadManager) {
+                                mSurfaceIsBad = true;
+                                sGLThreadManager.notifyAll();
+                            }
                             break;
                     }
+
+                    if (wantRenderNotification) {
+                        doRenderNotification = true;
+                    }
+                }
+
+            } finally {
+                /*
+                 * clean-up everything...
+                 */
+                synchronized (sGLThreadManager) {
+                    stopEglSurfaceLocked();
+                    stopEglContextLocked();
+                }
+            }
+        }
+
+        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();
+            }
+        }
+
+        public int getRenderMode() {
+            synchronized(sGLThreadManager) {
+                return mRenderMode;
+            }
+        }
+
+        public void requestRender() {
+            synchronized(sGLThreadManager) {
+                mRequestRender = true;
+                sGLThreadManager.notifyAll();
+            }
+        }
+
+        public void surfaceCreated() {
+            synchronized(sGLThreadManager) {
+                if (LOG_THREADS) {
+                    Log.i("GLThread", "surfaceCreated tid=" + getId());
+                }
+                mHasSurface = true;
+                mFinishedCreatingEglSurface = false;
+                sGLThreadManager.notifyAll();
+                while (mWaitingForSurface
+                       && !mFinishedCreatingEglSurface
+                       && !mExited) {
+                    try {
+                        sGLThreadManager.wait();
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
                 }
             }
-
-            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();
-                }
-            }
-        }
-
-        private void doResume() {
-            mPaused = false;
-            updateState();
-            if (mRenderMode == RENDERMODE_WHEN_DIRTY) {
-                requestRender();
-            }
-        }
-
-        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();
-        }
-
-        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() {
-            mGLHandler.runWithScissors(new Runnable() {
-                @Override
-                public void run() {
-                    doSurfaceCreated();
-                }
-            }, 0);
         }
 
         public void surfaceDestroyed() {
-            mGLHandler.runWithScissors(new Runnable() {
-                @Override
-                public void run() {
-                    doSurfaceDestroyed();
+            synchronized(sGLThreadManager) {
+                if (LOG_THREADS) {
+                    Log.i("GLThread", "surfaceDestroyed tid=" + getId());
                 }
-            }, 0);
+                mHasSurface = false;
+                sGLThreadManager.notifyAll();
+                while((!mWaitingForSurface) && (!mExited)) {
+                    try {
+                        sGLThreadManager.wait();
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
         }
 
         public void onPause() {
-            mGLHandler.runWithScissors(new Runnable() {
-                @Override
-                public void run() {
-                    doPause();
+            synchronized (sGLThreadManager) {
+                if (LOG_PAUSE_RESUME) {
+                    Log.i("GLThread", "onPause tid=" + getId());
                 }
-            }, 0);
+                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();
+                    }
+                }
+            }
         }
 
         public void onResume() {
-            mGLHandler.runWithScissors(new Runnable() {
-                @Override
-                public void run() {
-                    doResume();
+            synchronized (sGLThreadManager) {
+                if (LOG_PAUSE_RESUME) {
+                    Log.i("GLThread", "onResume tid=" + getId());
                 }
-            }, 0);
+                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();
+                    }
+                }
+            }
         }
 
         public void onWindowResize(int w, int h) {
-            final int width = w;
-            final int height = h;
-            mGLHandler.runWithScissors(new Runnable() {
-                @Override
-                public void run() {
-                    doWindowResize(width, height);
+            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();
+                    }
                 }
-            }, 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() {
-            getLooper().quit();
-            try {
-                this.join();
-            } catch (InterruptedException e) {
+            // 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();
+                    }
+                }
             }
         }
-    } // class GLThread
+
+        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 mFinishedCreatingEglSurface;
+        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;
+
+    }
 
     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);
                 }
             }
@@ -1641,7 +1792,7 @@
 
         private void flushBuilder() {
             if (mBuilder.length() > 0) {
-                Log.v(TAG, mBuilder.toString());
+                Log.v("GLSurfaceView", mBuilder.toString());
                 mBuilder.delete(0, mBuilder.length());
             }
         }
@@ -1649,10 +1800,141 @@
         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/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 9146ccd..2c25236 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,7 +55,10 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        }
+
         Intent intent = getIntent();
         String fingerprints = intent.getStringExtra("fingerprints");
         mKey = intent.getStringExtra("key");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7cb6b09..0fb3244 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -18,6 +18,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
+import android.app.IUiModeManager;
 import android.app.ProgressDialog;
 import android.app.SearchManager;
 import android.app.UiModeManager;
@@ -31,6 +32,7 @@
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -125,6 +127,11 @@
     static final boolean SHOW_STARTING_ANIMATIONS = true;
     static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
 
+    // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
+    // No longer recommended for desk docks; still useful in car docks.
+    static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
+    static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+
     static final int LONG_PRESS_POWER_NOTHING = 0;
     static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
     static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -247,12 +254,14 @@
     boolean mSystemReady;
     boolean mSystemBooted;
     boolean mHdmiPlugged;
+    int mUiMode;
     int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     int mLidOpenRotation;
     int mCarDockRotation;
     int mDeskDockRotation;
-    int mHdmiRotation;
-    boolean mHdmiRotationLock;
+    int mUndockedHdmiRotation;
+    int mDemoHdmiRotation;
+    boolean mDemoHdmiRotationLock;
 
     int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
     int mUserRotation = Surface.ROTATION_0;
@@ -831,6 +840,8 @@
         mSettingsObserver.observe();
         mShortcutManager = new ShortcutManager(context, mHandler);
         mShortcutManager.observe();
+        mUiMode = context.getResources().getInteger(
+                com.android.internal.R.integer.config_defaultUiModeType);
         mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
         mHomeIntent.addCategory(Intent.CATEGORY_HOME);
         mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -854,6 +865,8 @@
                 com.android.internal.R.integer.config_carDockRotation);
         mDeskDockRotation = readRotation(
                 com.android.internal.R.integer.config_deskDockRotation);
+        mUndockedHdmiRotation = readRotation(
+                com.android.internal.R.integer.config_undockedHdmiRotation);
         mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_carDockEnablesAccelerometer);
         mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
@@ -1024,11 +1037,11 @@
         // For demo purposes, allow the rotation of the HDMI display to be controlled.
         // By default, HDMI locks rotation to landscape.
         if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
-            mHdmiRotation = mPortraitRotation;
+            mDemoHdmiRotation = mPortraitRotation;
         } else {
-            mHdmiRotation = mLandscapeRotation;
+            mDemoHdmiRotation = mLandscapeRotation;
         }
-        mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
+        mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
     }
 
     @Override
@@ -3948,6 +3961,13 @@
             if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
                 mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
+            } else {
+                try {
+                    IUiModeManager uiModeService = IUiModeManager.Stub.asInterface(
+                            ServiceManager.getService(Context.UI_MODE_SERVICE));
+                    mUiMode = uiModeService.getCurrentModeType();
+                } catch (RemoteException e) {
+                }
             }
             updateRotation(true);
             synchronized (mLock) {
@@ -4200,10 +4220,17 @@
                 // enable 180 degree rotation while docked.
                 preferredRotation = mDeskDockEnablesAccelerometer
                         ? sensorRotation : mDeskDockRotation;
-            } else if (mHdmiPlugged && mHdmiRotationLock) {
-                // Ignore sensor when plugged into HDMI.
+            } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+                // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
                 // Note that the dock orientation overrides the HDMI orientation.
-                preferredRotation = mHdmiRotation;
+                preferredRotation = mDemoHdmiRotation;
+            } else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
+                    && mUndockedHdmiRotation >= 0) {
+                // Ignore sensor when plugged into HDMI and an undocked orientation has
+                // been specified in the configuration (only for legacy devices without
+                // full multi-display support).
+                // Note that the dock orientation overrides the HDMI orientation.
+                preferredRotation = mUndockedHdmiRotation;
             } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
                 // Application just wants to remain locked in the last rotation.
                 preferredRotation = lastRotation;
@@ -4577,9 +4604,70 @@
         }
     }
 
+    /**
+     * Return an Intent to launch the currently active dock app as home.  Returns
+     * null if the standard home should be launched, which is the case if any of the following is
+     * true:
+     * <ul>
+     *  <li>The device is not in either car mode or desk mode
+     *  <li>The device is in car mode but ENABLE_CAR_DOCK_HOME_CAPTURE is false
+     *  <li>The device is in desk mode but ENABLE_DESK_DOCK_HOME_CAPTURE is false
+     *  <li>The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME
+     *  <li>The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME
+     * </ul>
+     * @return
+     */
+    Intent createHomeDockIntent() {
+        Intent intent = null;
+
+        // What home does is based on the mode, not the dock state.  That
+        // is, when in car mode you should be taken to car home regardless
+        // of whether we are actually in a car dock.
+        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
+            if (ENABLE_CAR_DOCK_HOME_CAPTURE) {
+                intent = mCarDockIntent;
+            }
+        } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) {
+            if (ENABLE_DESK_DOCK_HOME_CAPTURE) {
+                intent = mDeskDockIntent;
+            }
+        }
+
+        if (intent == null) {
+            return null;
+        }
+
+        ActivityInfo ai = null;
+        ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
+                intent,
+                PackageManager.MATCH_DEFAULT_ONLY,
+                UserHandle.USER_CURRENT);
+        if (info != null) {
+            ai = info.activityInfo;
+        }
+        if (ai != null
+                && ai.metaData != null
+                && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
+            intent = new Intent(intent);
+            intent.setClassName(ai.packageName, ai.name);
+            return intent;
+        }
+
+        return null;
+    }
+
     void startDockOrHome() {
         awakenDreams();
-        // We don't have dock home anymore. Home is home. If you lived here, you'd be home by now.
+
+        Intent dock = createHomeDockIntent();
+        if (dock != null) {
+            try {
+                mContext.startActivityAsUser(dock, UserHandle.CURRENT);
+                return;
+            } catch (ActivityNotFoundException e) {
+            }
+        }
+
         mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
     }
     
@@ -4606,6 +4694,18 @@
                 } else {
                     ActivityManagerNative.getDefault().stopAppSwitches();
                     sendCloseSystemWindows();
+                    Intent dock = createHomeDockIntent();
+                    if (dock != null) {
+                        int result = ActivityManagerNative.getDefault()
+                                .startActivityAsUser(null, null, dock,
+                                        dock.resolveTypeIfNeeded(mContext.getContentResolver()),
+                                        null, null, 0,
+                                        ActivityManager.START_FLAG_ONLY_IF_NEEDED,
+                                        null, null, null, UserHandle.USER_CURRENT);
+                        if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
+                            return false;
+                        }
+                    }
                 }
                 int result = ActivityManagerNative.getDefault()
                         .startActivityAsUser(null, null, mHomeIntent,
@@ -4834,7 +4934,8 @@
             pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
                     pw.println(mLastFocusNeedsMenu);
         }
-        pw.print(prefix); pw.print("mDockMode="); pw.print(mDockMode);
+        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
+                pw.print(" mDockMode="); pw.print(mDockMode);
                 pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
                 pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation);
         pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
@@ -4967,7 +5068,8 @@
                 pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
         pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
                 pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
-        pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation);
-                pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock);
+        pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
+                pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
+        pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 7fcf1d5..fbeca4f6 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -1589,7 +1589,13 @@
 
     @Override
     public void cleanUp() {
-
+        // Make sure we let go of all widgets and their package contexts promptly. If we don't do
+        // this, and the associated application is uninstalled, it can cause a soft reboot.
+        int count = mAppWidgetContainer.getChildCount();
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame frame = mAppWidgetContainer.getWidgetPageAt(i);
+            frame.removeAllViews();
+        }
     }
 
     /**
@@ -1609,8 +1615,6 @@
         return !configDisabled || isTestHarness || fileOverride;
     }
 
-
-
     public void goToUserSwitcher() {
         mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_multi_user_selector));
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index 77359ff..9b588036 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -23,12 +23,16 @@
 import android.content.Context;
 import android.os.BatteryManager;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.View;
 import android.widget.TextView;
 
@@ -37,6 +41,8 @@
 import java.lang.ref.WeakReference;
 
 import com.android.internal.R;
+import com.android.internal.widget.ILockSettings;
+import com.android.internal.widget.LockPatternUtils;
 
 /***
  * Manages a number of views inside of the given layout. See below for a list of widgets.
@@ -57,6 +63,8 @@
     static final int SECURITY_MESSAGE_DURATION = 5000;
     protected static final int FADE_DURATION = 750;
 
+    private static final String TAG = "KeyguardMessageArea";
+
     // are we showing battery information?
     boolean mShowingBatteryInfo = false;
 
@@ -82,6 +90,9 @@
 
     CharSequence mMessage;
     boolean mShowingMessage;
+    private CharSequence mSeparator;
+    private LockPatternUtils mLockPatternUtils;
+
     Runnable mClearMessageRunnable = new Runnable() {
         @Override
         public void run() {
@@ -156,8 +167,6 @@
         }
     };
 
-    private CharSequence mSeparator;
-
     public KeyguardMessageArea(Context context) {
         this(context, null);
     }
@@ -165,6 +174,8 @@
     public KeyguardMessageArea(Context context, AttributeSet attrs) {
         super(context, attrs);
 
+        mLockPatternUtils = new LockPatternUtils(context);
+
         // This is required to ensure marquee works
         setSelected(true);
 
@@ -228,11 +239,12 @@
 
     String getOwnerInfo() {
         ContentResolver res = getContext().getContentResolver();
-        final boolean ownerInfoEnabled = Settings.Secure.getIntForUser(res,
-                Settings.Secure.LOCK_SCREEN_OWNER_INFO_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
-        return ownerInfoEnabled && !mShowingMessage ?
-                Settings.Secure.getStringForUser(res, Settings.Secure.LOCK_SCREEN_OWNER_INFO,
-                        UserHandle.USER_CURRENT) : null;
+        String info = null;
+        final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled();
+        if (ownerInfoEnabled && !mShowingMessage) {
+            info = mLockPatternUtils.getOwnerInfo(mLockPatternUtils.getCurrentUser());
+        }
+        return info;
     }
 
     private CharSequence getChargeInfo(MutableInt icon) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a28c387..f872cc3 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1595,7 +1595,7 @@
                     ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(),
                             PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                             mSettings.getCurrentUserId());
-                    if (ai.enabledSetting
+                    if (ai != null && ai.enabledSetting
                             == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                         mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
                                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index e20a21f..41cc4d7 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -19,6 +19,11 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+
+import static android.content.Context.USER_SERVICE;
+import static android.Manifest.permission.READ_PROFILE;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
@@ -27,8 +32,10 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -40,6 +47,7 @@
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Keeps the lock pattern/password data and related settings for each user.
@@ -79,23 +87,52 @@
 
     private void migrateOldData() {
         try {
-            if (getString("migrated", null, 0) != null) {
-                // Already migrated
-                return;
+            // These Settings moved before multi-user was enabled, so we only have to do it for the
+            // root user.
+            if (getString("migrated", null, 0) == null) {
+                final ContentResolver cr = mContext.getContentResolver();
+                for (String validSetting : VALID_SETTINGS) {
+                    String value = Settings.Secure.getString(cr, validSetting);
+                    if (value != null) {
+                        setString(validSetting, value, 0);
+                    }
+                }
+                // No need to move the password / pattern files. They're already in the right place.
+                setString("migrated", "true", 0);
+                Slog.i(TAG, "Migrated lock settings to new location");
             }
 
-            final ContentResolver cr = mContext.getContentResolver();
-            for (String validSetting : VALID_SETTINGS) {
-                String value = Settings.Secure.getString(cr, validSetting);
-                if (value != null) {
-                    setString(validSetting, value, 0);
+            // These Settings changed after multi-user was enabled, hence need to be moved per user.
+            if (getString("migrated_user_specific", null, 0) == null) {
+                final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+                final ContentResolver cr = mContext.getContentResolver();
+                List<UserInfo> users = um.getUsers();
+                for (int user = 0; user < users.size(); user++) {
+                    int userId = users.get(user).getUserHandle().getIdentifier();
+                    for (String perUserSetting : MIGRATE_SETTINGS_PER_USER) {
+                        // Handle Strings
+                        String value = Settings.Secure.getStringForUser(cr, perUserSetting, userId);
+                        if (value != null) {
+                            setString(perUserSetting, value, userId);
+                            Settings.Secure.putStringForUser(cr, perUserSetting, "", userId);
+                            continue;
+                        }
+
+                        // Handle integers
+                        try {
+                            int ivalue = Settings.Secure.getIntForUser(cr, perUserSetting, userId);
+                            setLong(perUserSetting, ivalue, userId);
+                            Settings.Secure.putIntForUser(cr, perUserSetting, 0, userId);
+                        } catch (SettingNotFoundException e) {
+                        }
+                    }
                 }
+                // No need to move the password / pattern files. They're already in the right place.
+                setString("migrated_user_specific", "true", 0);
+                Slog.i(TAG, "Migrated per-user lock settings to new location");
             }
-            // No need to move the password / pattern files. They're already in the right place.
-            setString("migrated", "true", 0);
-            Slog.i(TAG, "Migrated lock settings to new location");
         } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to migrate old data");
+            Slog.e(TAG, "Unable to migrate old data", re);
         }
     }
 
@@ -115,12 +152,16 @@
         }
     }
 
-    private static final void checkReadPermission(int userId) {
+    private final void checkReadPermission(String requestedKey, int userId) {
         final int callingUid = Binder.getCallingUid();
-        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID
-                && UserHandle.getUserId(callingUid) != userId) {
-            throw new SecurityException("uid=" + callingUid
-                    + " not authorized to read settings of user " + userId);
+        for (int i = 0; i < READ_PROFILE_PROTECTED_SETTINGS.length; i++) {
+            String key = READ_PROFILE_PROTECTED_SETTINGS[i];
+            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_PROFILE)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("uid=" + callingUid
+                        + " needs permission " + READ_PROFILE + " to read "
+                        + requestedKey + " for user " + userId);
+            }
         }
     }
 
@@ -147,7 +188,7 @@
 
     @Override
     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
-        //checkReadPermission(userId);
+        checkReadPermission(key, userId);
 
         String value = readFromDb(key, null, userId);
         return TextUtils.isEmpty(value) ?
@@ -156,7 +197,7 @@
 
     @Override
     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
-        //checkReadPermission(userId);
+        checkReadPermission(key, userId);
 
         String value = readFromDb(key, null, userId);
         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
@@ -164,7 +205,7 @@
 
     @Override
     public String getString(String key, String defaultValue, int userId) throws RemoteException {
-        //checkReadPermission(userId);
+        checkReadPermission(key, userId);
 
         return readFromDb(key, defaultValue, userId);
     }
@@ -404,5 +445,13 @@
         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
         Secure.LOCK_PATTERN_VISIBLE,
         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
-        };
+    };
+
+    private static final String[] MIGRATE_SETTINGS_PER_USER = new String[] {
+        Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+        Secure.LOCK_SCREEN_OWNER_INFO
+    };
+
+    // These are protected with a read permission
+    private static final String[] READ_PROFILE_PROTECTED_SETTINGS = MIGRATE_SETTINGS_PER_USER;
 }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index fa18e76..9a93f63 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -450,11 +450,16 @@
 
     public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
         checkCallerIsSystem();
-        if (true||DBG) {
-            Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
-        }
+
+        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
+
         mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
                 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+
+        // Now, cancel any outstanding notifications that are part of a just-disabled app
+        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+            cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
+        }
     }
 
 
@@ -1676,8 +1681,12 @@
                 .getSystemService(Context.AUDIO_SERVICE);
 
                 // sound
+
+                // should we use the default notification sound? (indicated either by DEFAULT_SOUND
+                // or because notification.sound is pointing at Settings.System.NOTIFICATION_SOUND)
                 final boolean useDefaultSound =
-                    (notification.defaults & Notification.DEFAULT_SOUND) != 0;
+                       (notification.defaults & Notification.DEFAULT_SOUND) != 0
+                    || Settings.System.DEFAULT_NOTIFICATION_URI.equals(notification.sound);
 
                 Uri soundUri = null;
                 boolean hasValidSound = false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a30fc3b..681c21d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -26,6 +26,7 @@
 import android.content.res.Configuration;
 import android.media.AudioService;
 import android.net.wifi.p2p.WifiP2pService;
+import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -1055,6 +1056,8 @@
         // as efficient as possible with its memory usage.
         VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
 
+        Environment.setUserRequired(true);
+
         System.loadLibrary("android_servers");
         init1(args);
     }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1f3ac96..2f64908 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -237,6 +237,11 @@
                     }
                     // We will update when the automation service dies.
                     UserState userState = getCurrentUserStateLocked();
+                    // We have to reload the installed services since some services may
+                    // have different attributes, resolve info (does not support equals),
+                    // etc. Remove them then to force reload. Do it even if automation is
+                    // running since when it goes away, we will have to reload as well.
+                    userState.mInstalledServices.clear();
                     if (userState.mUiAutomationService == null) {
                         if (readConfigurationForUserStateLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -820,17 +825,21 @@
 
     private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) {
         // TODO: Now we are giving the key events to the last enabled
-        //       service that can handle them which is the last one
-        //       in our list since we write the last enabled as the
-        //       last record in the enabled services setting. Ideally,
-        //       the user should make the call which service handles
-        //       key events. However, only one service should handle
-        //       key events to avoid user frustration when different
-        //       behavior is observed from different combinations of
-        //       enabled accessibility services.
+        //       service that can handle them Ideally, the user should
+        //       make the call which service handles key events. However,
+        //       only one service should handle key events to avoid user
+        //       frustration when different behavior is observed from
+        //       different combinations of enabled accessibility services.
         UserState state = getCurrentUserStateLocked();
         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
             Service service = state.mBoundServices.get(i);
+            // Key events are handled only by services that declared
+            // this capability and requested to filter key events.
+            if (!service.mRequestFilterKeyEvents ||
+                    (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo
+                            .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
+                continue;
+            }
             if (service.mIsDefault == isDefault) {
                 service.notifyKeyEvent(event, policyFlags);
                 return true;
@@ -1160,7 +1169,9 @@
         boolean setInputFilter = false;
         AccessibilityInputFilter inputFilter = null;
         synchronized (mLock) {
-            if (userState.mIsAccessibilityEnabled) {
+            // Accessibility enabled means at least one service is enabled.
+            if (userState.mIsAccessibilityEnabled
+                    || userState.mIsDisplayMagnificationEnabled) {
                 if (!mHasInputFilter) {
                     mHasInputFilter = true;
                     if (mInputFilter == null) {
@@ -1174,7 +1185,8 @@
                 if (userState.mIsDisplayMagnificationEnabled) {
                     flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
                 }
-                if (userState.mIsTouchExplorationEnabled) {
+                // Touch exploration without accessibility makes no sense.
+                if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
                     flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
                 }
                 mInputFilter.setEnabledFeatures(flags);
@@ -1366,11 +1378,11 @@
                 return true;
             }
         } else {
-            // Starting in JB-MR2 we request a permission to allow a service to enable
-            // touch exploration and do not care if the service is in the white list.
-            if (mContext.getPackageManager().checkPermission(
-                    android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
-                    service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+            // Starting in JB-MR2 we request an accessibility service to declare
+            // certain capabilities in its meta-data to allow it to enable the
+            // corresponding features.
+            if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
+                    & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) {
                 userState.mIsTouchExplorationEnabled = true;
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
@@ -1399,9 +1411,8 @@
         if (userState.mIsEnhancedWebAccessibilityEnabled) {
             return false;
         }
-        if (service.mIsAutomation || mContext.getPackageManager().checkPermission(
-                android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
-                service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+        if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
+               & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) {
             userState.mIsEnhancedWebAccessibilityEnabled = true;
             Settings.Secure.putIntForUser(mContext.getContentResolver(),
                     Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
@@ -1636,6 +1647,8 @@
 
         boolean mRequestEnhancedWebAccessibility;
 
+        boolean mRequestFilterKeyEvents;
+
         int mFetchFlags;
 
         long mNotificationTimeout;
@@ -1681,7 +1694,8 @@
             mAccessibilityServiceInfo = accessibilityServiceInfo;
             mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
             if (!mIsAutomation) {
-                mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
+                mCanRetrieveScreenContent = (accessibilityServiceInfo.getCapabilities()
+                        & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0;
                 mIntent = new Intent().setComponent(mComponentName);
                 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                         com.android.internal.R.string.accessibility_binding_label);
@@ -1720,9 +1734,11 @@
 
             if (mResolveInfo != null) {
                 mRequestTouchExplorationMode = (info.flags
-                            & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+                        & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
                 mRequestEnhancedWebAccessibility = (info.flags
-                           & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+                        & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+                mRequestFilterKeyEvents = (info.flags
+                        & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS)  != 0;
             }
         }
 
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index fd7cd78..241b224 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -30,6 +30,7 @@
 import android.accounts.IAccountManagerResponse;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -1874,6 +1875,20 @@
         return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid);
     }
 
+    @Override
+    public Account[] getAccountsByTypeForPackage(String type, String packageName) {
+        checkBinderPermission(android.Manifest.permission.INTERACT_ACROSS_USERS);
+        int packageUid = -1;
+        try {
+            packageUid = AppGlobals.getPackageManager().getPackageUid(
+                    packageName, UserHandle.getCallingUserId());
+        } catch (RemoteException re) {
+            Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
+            return new Account[0];
+        }
+        return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
+    }
+
     public void getAccountsByFeatures(IAccountManagerResponse response,
             String type, String[] features) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bc1df85..1d17da9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4967,6 +4967,10 @@
             return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
                     owningUid, exported);
         }
+
+        public Object getAMSLock() {
+            return ActivityManagerService.this;
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java
index 0688c50..de439d7 100644
--- a/services/java/com/android/server/am/NativeCrashListener.java
+++ b/services/java/com/android/server/am/NativeCrashListener.java
@@ -43,13 +43,14 @@
 class NativeCrashListener extends Thread {
     static final String TAG = "NativeCrashListener";
     static final boolean DEBUG = false;
+    static final boolean MORE_DEBUG = DEBUG && false;
 
     // Must match the path defined in debuggerd.c.
     static final String DEBUGGERD_SOCKET_PATH = "/data/system/ndebugsocket";
 
     // Use a short timeout on socket operations and abandon the connection
     // on hard errors
-    static final long SOCKET_TIMEOUT_MILLIS = 1000;  // 1 second
+    static final long SOCKET_TIMEOUT_MILLIS = 2000;  // 2 seconds
 
     final ActivityManagerService mAm;
 
@@ -124,9 +125,9 @@
                 InetSocketAddress peer = new InetSocketAddress();
                 FileDescriptor peerFd = null;
                 try {
-                    if (DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
+                    if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
                     peerFd = Libcore.os.accept(serverFd, peer);
-                    if (DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
+                    if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
                     if (peerFd != null) {
                         // Only the superuser is allowed to talk to us over this socket
                         StructUcred credentials =
@@ -145,7 +146,12 @@
                     if (peerFd != null) {
                         try {
                             Libcore.os.write(peerFd, ackSignal, 0, 1);
-                        } catch (Exception e) { /* we don't care about failures here */ }
+                        } catch (Exception e) {
+                            /* we don't care about failures here */
+                            if (MORE_DEBUG) {
+                                Slog.d(TAG, "Exception writing ack: " + e.getMessage());
+                            }
+                        }
                     }
                 }
             }
@@ -183,7 +189,7 @@
 
     // Read the crash report from the debuggerd connection
     void consumeNativeCrashData(FileDescriptor fd) {
-        if (DEBUG) Slog.i(TAG, "debuggerd connected");
+        if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
         final byte[] buf = new byte[4096];
         final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);
 
@@ -218,7 +224,7 @@
                         // get some data
                         bytes = Libcore.os.read(fd, buf, 0, buf.length);
                         if (bytes > 0) {
-                            if (DEBUG) {
+                            if (MORE_DEBUG) {
                                 String s = new String(buf, 0, bytes, "UTF-8");
                                 Slog.v(TAG, "READ=" + bytes + "> " + s);
                             }
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index a83675e..8c8b360 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -481,6 +481,7 @@
             mRemoteDisplayConnected = false;
             mHandler.removeCallbacks(mRtspTimeout);
 
+            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_DISABLED);
             setRemoteSubmixOn(false);
             unadvertiseDisplay();
 
@@ -626,6 +627,7 @@
             }
 
             setRemoteSubmixOn(true);
+            mWifiP2pManager.setMiracastMode(WifiP2pManager.MIRACAST_SOURCE);
 
             final WifiP2pDevice oldDevice = mConnectedDevice;
             final int port = getPortNumber(mConnectedDevice);
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index 08e6b45..edba2431 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -25,6 +25,9 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.Environment;
+import android.os.FileObserver;
+import android.os.Handler;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
 import android.util.Xml;
@@ -58,19 +61,18 @@
     private static final String TAG_BROADCAST = "broadcast";
 
     private static final int TYPE_ACTIVITY = 0;
-    private static final int TYPE_SERVICE = 1;
-    private static final int TYPE_BROADCAST = 2;
+    private static final int TYPE_BROADCAST = 1;
+    private static final int TYPE_SERVICE = 2;
 
     private static final HashMap<String, FilterFactory> factoryMap;
 
     private final AMSInterface mAms;
 
-    private final IntentResolver<FirewallIntentFilter, Rule> mActivityResolver =
-            new FirewallIntentResolver();
-    private final IntentResolver<FirewallIntentFilter, Rule> mServiceResolver =
-            new FirewallIntentResolver();
-    private final IntentResolver<FirewallIntentFilter, Rule> mBroadcastResolver =
-            new FirewallIntentResolver();
+    private final RuleObserver mObserver;
+
+    private FirewallIntentResolver mActivityResolver = new FirewallIntentResolver();
+    private FirewallIntentResolver mBroadcastResolver = new FirewallIntentResolver();
+    private FirewallIntentResolver mServiceResolver = new FirewallIntentResolver();
 
     static {
         FilterFactory[] factories = new FilterFactory[] {
@@ -104,9 +106,18 @@
 
     public IntentFirewall(AMSInterface ams) {
         mAms = ams;
-        readRules(getRulesFile());
+        File rulesFile = getRulesFile();
+
+        readRules(rulesFile);
+
+        mObserver = new RuleObserver(rulesFile);
+        mObserver.startWatching();
     }
 
+    /**
+     * This is called from ActivityManager to check if a start activity intent should be allowed.
+     * It is assumed the caller is already holding the global ActivityManagerService lock.
+     */
     public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp, int callerUid,
             int callerPid, String resolvedType, ActivityInfo resolvedActivity) {
         List<Rule> matchingRules = mActivityResolver.queryIntent(intent, resolvedType, false, 0);
@@ -208,7 +219,18 @@
         return RULES_FILE;
     }
 
+    /**
+     * Reads rules from the given file and replaces our set of rules with the newly read rules
+     *
+     * All calls to this method from the file observer come through a handler and are inherently
+     * serialized
+     */
     private void readRules(File rulesFile) {
+        FirewallIntentResolver[] resolvers = new FirewallIntentResolver[3];
+        for (int i=0; i<resolvers.length; i++) {
+            resolvers[i] = new FirewallIntentResolver();
+        }
+
         FileInputStream fis;
         try {
             fis = new FileInputStream(rulesFile);
@@ -224,40 +246,59 @@
 
             XmlUtils.beginDocument(parser, TAG_RULES);
 
+            int[] numRules = new int[3];
+
             int outerDepth = parser.getDepth();
             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-                IntentResolver<FirewallIntentFilter, Rule> resolver = null;
+                int ruleType = -1;
+
                 String tagName = parser.getName();
                 if (tagName.equals(TAG_ACTIVITY)) {
-                    resolver = mActivityResolver;
-                } else if (tagName.equals(TAG_SERVICE)) {
-                    resolver = mServiceResolver;
+                    ruleType = TYPE_ACTIVITY;
                 } else if (tagName.equals(TAG_BROADCAST)) {
-                    resolver = mBroadcastResolver;
+                    ruleType = TYPE_BROADCAST;
+                } else if (tagName.equals(TAG_SERVICE)) {
+                    ruleType = TYPE_SERVICE;
                 }
 
-                if (resolver != null) {
+                if (ruleType != -1) {
                     Rule rule = new Rule();
 
+                    FirewallIntentResolver resolver = resolvers[ruleType];
+
+                    // if we get an error while parsing a particular rule, we'll just ignore
+                    // that rule and continue on with the next rule
                     try {
                         rule.readFromXml(parser);
                     } catch (XmlPullParserException ex) {
                         Slog.e(TAG, "Error reading intent firewall rule", ex);
                         continue;
-                    } catch (IOException ex) {
-                        Slog.e(TAG, "Error reading intent firewall rule", ex);
-                        continue;
                     }
 
+                    numRules[ruleType]++;
+
                     for (int i=0; i<rule.getIntentFilterCount(); i++) {
                         resolver.addFilter(rule.getIntentFilter(i));
                     }
                 }
             }
+
+            Slog.i(TAG, "Read new rules (A:" + numRules[TYPE_ACTIVITY] +
+                    " B:" + numRules[TYPE_BROADCAST] + " S:" + numRules[TYPE_SERVICE] + ")");
+
+            synchronized (mAms.getAMSLock()) {
+                mActivityResolver = resolvers[TYPE_ACTIVITY];
+                mBroadcastResolver = resolvers[TYPE_BROADCAST];
+                mServiceResolver = resolvers[TYPE_SERVICE];
+            }
         } catch (XmlPullParserException ex) {
+            // if there was an error outside of a specific rule, then there are probably
+            // structural problems with the xml file, and we should completely ignore it
             Slog.e(TAG, "Error reading intent firewall rules", ex);
+            clearRules();
         } catch (IOException ex) {
             Slog.e(TAG, "Error reading intent firewall rules", ex);
+            clearRules();
         } finally {
             try {
                 fis.close();
@@ -267,6 +308,22 @@
         }
     }
 
+    /**
+     * Clears out all of our rules
+     *
+     * All calls to this method from the file observer come through a handler and are inherently
+     * serialized
+     */
+    private void clearRules() {
+        Slog.i(TAG, "Clearing all rules");
+
+        synchronized (mAms.getAMSLock())  {
+            mActivityResolver = new FirewallIntentResolver();
+            mBroadcastResolver = new FirewallIntentResolver();
+            mServiceResolver = new FirewallIntentResolver();
+        }
+    }
+
     static Filter parseFilter(XmlPullParser parser) throws IOException, XmlPullParserException {
         String elementName = parser.getName();
 
@@ -363,6 +420,58 @@
         }
     }
 
+    private static final int READ_RULES = 0;
+    private static final int CLEAR_RULES = 1;
+
+    final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case READ_RULES:
+                    readRules(getRulesFile());
+                    break;
+                case CLEAR_RULES:
+                    clearRules();
+                    break;
+            }
+        }
+    };
+
+    /**
+     * Monitors for the creation/deletion/modification of the rule file
+     */
+    private class RuleObserver extends FileObserver {
+        // The file name we're monitoring, with no path component
+        private final String mMonitoredFile;
+
+        private static final int CREATED_FLAGS = FileObserver.CREATE|FileObserver.MOVED_TO|
+                FileObserver.CLOSE_WRITE;
+        private static final int DELETED_FLAGS = FileObserver.DELETE|FileObserver.MOVED_FROM;
+
+        public RuleObserver(File monitoredFile) {
+            super(monitoredFile.getParentFile().getAbsolutePath(), CREATED_FLAGS|DELETED_FLAGS);
+            mMonitoredFile = monitoredFile.getName();
+        }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if (path.equals(mMonitoredFile)) {
+                // we wait 250ms before taking any action on an event, in order to dedup multiple
+                // events. E.g. a delete event followed by a create event followed by a subsequent
+                // write+close event;
+                if ((event & CREATED_FLAGS) != 0) {
+                    mHandler.removeMessages(READ_RULES);
+                    mHandler.removeMessages(CLEAR_RULES);
+                    mHandler.sendEmptyMessageDelayed(READ_RULES, 250);
+                } else if ((event & DELETED_FLAGS) != 0) {
+                    mHandler.removeMessages(READ_RULES);
+                    mHandler.removeMessages(CLEAR_RULES);
+                    mHandler.sendEmptyMessageDelayed(CLEAR_RULES, 250);
+                }
+            }
+        }
+    }
+
     /**
      * This interface contains the methods we need from ActivityManagerService. This allows AMS to
      * export these methods to us without making them public, and also makes it easier to test this
@@ -371,6 +480,7 @@
     public interface AMSInterface {
         int checkComponentPermission(String permission, int pid, int uid,
                 int owningUid, boolean exported);
+        Object getAMSLock();
     }
 
     /**
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index df90a56..11c6dab 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -88,8 +88,13 @@
     private static final String TAG_ENTRY = "entry";
     private static final String TAG_VALUE = "value";
     private static final String ATTR_KEY = "key";
+    private static final String ATTR_VALUE_TYPE = "type";
     private static final String ATTR_MULTIPLE = "m";
 
+    private static final String ATTR_TYPE_STRING_ARRAY = "sa";
+    private static final String ATTR_TYPE_STRING = "s";
+    private static final String ATTR_TYPE_BOOLEAN = "b";
+
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
     private static final String USER_PHOTO_FILENAME = "photo.png";
@@ -965,7 +970,12 @@
     }
 
     @Override
-    public List<RestrictionEntry> getApplicationRestrictions(String packageName, int userId) {
+    public Bundle getApplicationRestrictions(String packageName) {
+        return getApplicationRestrictionsForUser(packageName, UserHandle.getCallingUserId());
+    }
+
+    @Override
+    public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
         if (UserHandle.getCallingUserId() != userId
                 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
             checkManageUsersPermission("Only system can get restrictions for other users/apps");
@@ -977,7 +987,7 @@
     }
 
     @Override
-    public void setApplicationRestrictions(String packageName, List<RestrictionEntry> entries,
+    public void setApplicationRestrictions(String packageName, Bundle restrictions,
             int userId) {
         if (UserHandle.getCallingUserId() != userId
                 || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
@@ -985,7 +995,7 @@
         }
         synchronized (mPackagesLock) {
             // Write the restrictions to XML
-            writeApplicationRestrictionsLocked(packageName, entries, userId);
+            writeApplicationRestrictionsLocked(packageName, restrictions, userId);
         }
     }
 
@@ -1001,9 +1011,9 @@
         }
     }
 
-    private List<RestrictionEntry> readApplicationRestrictionsLocked(String packageName,
+    private Bundle readApplicationRestrictionsLocked(String packageName,
             int userId) {
-        final ArrayList<RestrictionEntry> entries = new ArrayList<RestrictionEntry>();
+        final Bundle restrictions = new Bundle();
         final ArrayList<String> values = new ArrayList<String>();
 
         FileInputStream fis = null;
@@ -1023,12 +1033,13 @@
             if (type != XmlPullParser.START_TAG) {
                 Slog.e(LOG_TAG, "Unable to read restrictions file "
                         + restrictionsFile.getBaseFile());
-                return entries;
+                return restrictions;
             }
 
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
                     String key = parser.getAttributeValue(null, ATTR_KEY);
+                    String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
                     String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
                     if (multiple != null) {
                         int count = Integer.parseInt(multiple);
@@ -1041,14 +1052,13 @@
                         }
                         String [] valueStrings = new String[values.size()];
                         values.toArray(valueStrings);
-                        Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + valueStrings);
-                        RestrictionEntry entry = new RestrictionEntry(key, valueStrings);
-                        entries.add(entry);
+                        restrictions.putStringArray(key, valueStrings);
+                    } else if (ATTR_TYPE_BOOLEAN.equals(valType)) {
+                        restrictions.putBoolean(key, Boolean.parseBoolean(
+                                parser.nextText().trim()));
                     } else {
                         String value = parser.nextText().trim();
-                        Slog.d(LOG_TAG, "Got RestrictionEntry " + key + "," + value);
-                        RestrictionEntry entry = new RestrictionEntry(key, value);
-                        entries.add(entry);
+                        restrictions.putString(key, value);
                     }
                 }
             }
@@ -1063,11 +1073,11 @@
                 }
             }
         }
-        return entries;
+        return restrictions;
     }
 
     private void writeApplicationRestrictionsLocked(String packageName,
-            List<RestrictionEntry> entries, int userId) {
+            Bundle restrictions, int userId) {
         FileOutputStream fos = null;
         AtomicFile restrictionsFile = new AtomicFile(
                 new File(Environment.getUserSystemDirectory(userId),
@@ -1084,18 +1094,24 @@
 
             serializer.startTag(null, TAG_RESTRICTIONS);
 
-            for (RestrictionEntry entry : entries) {
+            for (String key : restrictions.keySet()) {
+                Object value = restrictions.get(key);
                 serializer.startTag(null, TAG_ENTRY);
-                serializer.attribute(null, ATTR_KEY, entry.getKey());
-                if (entry.getSelectedString() != null || entry.getAllSelectedStrings() == null) {
-                    String value = entry.getSelectedString();
-                    serializer.text(value != null ? value : "");
+                serializer.attribute(null, ATTR_KEY, key);
+
+                if (value instanceof Boolean) {
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
+                    serializer.text(value.toString());
+                } else if (value == null || value instanceof String) {
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
+                    serializer.text(value != null ? (String) value : "");
                 } else {
-                    String[] values = entry.getAllSelectedStrings();
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
+                    String[] values = (String[]) value;
                     serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
-                    for (String value : values) {
+                    for (String choice : values) {
                         serializer.startTag(null, TAG_VALUE);
-                        serializer.text(value != null ? value : "");
+                        serializer.text(choice != null ? choice : "");
                         serializer.endTag(null, TAG_VALUE);
                     }
                 }
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index 4d23e5c..9560199 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -404,7 +404,7 @@
         try {
 
             /* Turning off Wi-Fi when scans are still available */
-            if (!enable && isScanningAlwaysAvailable()) {
+            if (!enable && isScanAlwaysAvailable()) {
                 /* 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);
@@ -497,7 +497,7 @@
      * @return {@code true} if the enable/disable operation was
      *         started or is already in the queue.
      */
-    public boolean isScanningAlwaysAvailable() {
+    public boolean isScanAlwaysAvailable() {
         enforceAccessPermission();
         return mSettingsStore.isScanAlwaysAvailable();
     }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1d1fda5..bc442ce 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5490,6 +5490,7 @@
         ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
         matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
         Canvas canvas = new Canvas(bm);
+        canvas.drawColor(0xFF000000);
         canvas.drawBitmap(rawss, matrix, null);
         canvas.setBitmap(null);
 
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 31e01c0..dbd48d9 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -93,21 +93,21 @@
     }
 
     /**
-     * @return Network Id 0..65535
+     * @return Network Id 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getNetworkId() {
         return mNetworkId;
     }
 
     /**
-     * @return System Id 0..32767
+     * @return System Id 0..32767, Integer.MAX_VALUE if unknown
      */
     public int getSystemId() {
         return mSystemId;
     }
 
     /**
-     * @return Base Station Id 0..65535
+     * @return Base Station Id 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getBasestationId() {
         return mBasestationId;
@@ -118,7 +118,7 @@
      * specified in 3GPP2 C.S0005-A v6.0. It is represented in units
      * of 0.25 seconds and ranges from -2592000 to 2592000, both
      * values inclusive (corresponding to a range of -180
-     * to +180 degrees).
+     * to +180 degrees). Integer.MAX_VALUE if unknown.
      */
     public int getLongitude() {
         return mLongitude;
@@ -129,7 +129,7 @@
      * specified in 3GPP2 C.S0005-A v6.0. It is represented in units
      * of 0.25 seconds and ranges from -1296000 to 1296000, both
      * values inclusive (corresponding to a range of -90
-     * to +90 degrees).
+     * to +90 degrees). Integer.MAX_VALUE if unknown.
      */
     public int getLatitude() {
         return mLatitude;
@@ -162,7 +162,7 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentitiyCdma:{");
+        StringBuilder sb = new StringBuilder("CellIdentityCdma:{");
         sb.append(" mNetworkId="); sb.append(mNetworkId);
         sb.append(" mSystemId="); sb.append(mSystemId);
         sb.append(" mBasestationId="); sb.append(mBasestationId);
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 98113e7..6f8cc91 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -21,7 +21,7 @@
 import android.telephony.Rlog;
 
 /**
- * CellIdentity to represent a unique GSM or UMTS cell
+ * CellIdentity to represent a unique GSM cell
  */
 public final class CellIdentityGsm implements Parcelable {
 
@@ -35,10 +35,7 @@
     // 16-bit Location Area Code, 0..65535
     private final int mLac;
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
-    // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
     private final int mCid;
-    // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
-    private final int mPsc;
 
     /**
      * @hide
@@ -48,7 +45,6 @@
         mMnc = Integer.MAX_VALUE;
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
-        mPsc = Integer.MAX_VALUE;
     }
     /**
      * public constructor
@@ -56,16 +52,14 @@
      * @param mnc 2 or 3-digit Mobile Network Code, 0..999
      * @param lac 16-bit Location Area Code, 0..65535
      * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
-     * @param psc 9-bit UMTS Primary Scrambling Code
      *
      * @hide
      */
-    public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int psc) {
+    public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
         mMcc = mcc;
         mMnc = mnc;
         mLac = lac;
         mCid = cid;
-        mPsc = psc;
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
@@ -73,7 +67,6 @@
         mMnc = cid.mMnc;
         mLac = cid.mLac;
         mCid = cid.mCid;
-        mPsc = cid.mPsc;
     }
 
     CellIdentityGsm copy() {
@@ -81,21 +74,21 @@
     }
 
     /**
-     * @return 3-digit Mobile Country Code, 0..999
+     * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMcc() {
         return mMcc;
     }
 
     /**
-     * @return 2 or 3-digit Mobile Network Code, 0..999
+     * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMnc() {
         return mMnc;
     }
 
     /**
-     * @return 16-bit Location Area Code, 0..65535
+     * @return 16-bit Location Area Code, 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getLac() {
         return mLac;
@@ -104,27 +97,24 @@
     /**
      * @return CID
      * Either 16-bit GSM Cell Identity described
-     * in TS 27.007, 0..65535
-     * or 28-bit UMTS Cell Identity described
-     * in TS 25.331, 0..268435455
+     * in TS 27.007, 0..65535, Integer.MAX_VALUE if unknown
      */
     public int getCid() {
         return mCid;
     }
 
     /**
-     * @return 9-bit UMTS Primary Scrambling Code described in
-     * TS 25.331, 0..511
+     * @return Integer.MAX_VALUE, undefined for GSM
      */
+    @Deprecated
     public int getPsc() {
-        return mPsc;
+        return Integer.MAX_VALUE;
     }
 
     @Override
     public int hashCode() {
         int primeNum = 31;
-        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
-                (mPsc * primeNum);
+        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum);
     }
 
     @Override
@@ -135,8 +125,7 @@
                 return mMcc == o.mMcc &&
                         mMnc == o.mMnc &&
                         mLac == o.mLac &&
-                        mCid == o.mCid &&
-                        mPsc == o.mPsc;
+                        mCid == o.mCid;
             } catch (ClassCastException e) {
                 return false;
             }
@@ -147,12 +136,11 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentitiyGsm:{");
+        StringBuilder sb = new StringBuilder("CellIdentityGsm:{");
         sb.append(" mMcc=").append(mMcc);
         sb.append(" mMnc=").append(mMnc);
         sb.append(" mLac=").append(mLac);
         sb.append(" mCid=").append(mCid);
-        sb.append(" mPsc=").append(mPsc);
         sb.append("}");
 
         return sb.toString();
@@ -172,7 +160,6 @@
         dest.writeInt(mMnc);
         dest.writeInt(mLac);
         dest.writeInt(mCid);
-        dest.writeInt(mPsc);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -181,7 +168,6 @@
         mMnc = in.readInt();
         mLac = in.readInt();
         mCid = in.readInt();
-        mPsc = in.readInt();
         if (DBG) log("CellIdentityGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 86924bd..13b39c9 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -81,35 +81,35 @@
     }
 
     /**
-     * @return 3-digit Mobile Country Code, 0..999
+     * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMcc() {
         return mMcc;
     }
 
     /**
-     * @return 2 or 3-digit Mobile Network Code, 0..999
+     * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
      */
     public int getMnc() {
         return mMnc;
     }
 
     /**
-     * @return 28-bit Cell Identity
+     * @return 28-bit Cell Identity, Integer.MAX_VALUE if unknown
      */
     public int getCi() {
         return mCi;
     }
 
     /**
-     * @return Physical Cell Id 0..503
+     * @return Physical Cell Id 0..503, Integer.MAX_VALUE if unknown
      */
     public int getPci() {
         return mPci;
     }
 
     /**
-     * @return 16-bit Tracking Area Code
+     * @return 16-bit Tracking Area Code, Integer.MAX_VALUE if unknown
      */
     public int getTac() {
         return mTac;
@@ -142,7 +142,7 @@
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder("CellIdentitiyLte:{");
+        StringBuilder sb = new StringBuilder("CellIdentityLte:{");
         sb.append(" mMcc="); sb.append(mMcc);
         sb.append(" mMnc="); sb.append(mMnc);
         sb.append(" mCi="); sb.append(mCi);
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
new file mode 100644
index 0000000..2f8fa42
--- /dev/null
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * CellIdentity to represent a unique UMTS cell
+ */
+public final class CellIdentityWcdma implements Parcelable {
+
+    private static final String LOG_TAG = "CellIdentityWcdma";
+    private static final boolean DBG = false;
+
+    // 3-digit Mobile Country Code, 0..999
+    private final int mMcc;
+    // 2 or 3-digit Mobile Network Code, 0..999
+    private final int mMnc;
+    // 16-bit Location Area Code, 0..65535
+    private final int mLac;
+    // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
+    private final int mCid;
+    // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
+    private final int mPsc;
+
+    /**
+     * @hide
+     */
+    public CellIdentityWcdma() {
+        mMcc = Integer.MAX_VALUE;
+        mMnc = Integer.MAX_VALUE;
+        mLac = Integer.MAX_VALUE;
+        mCid = Integer.MAX_VALUE;
+        mPsc = Integer.MAX_VALUE;
+    }
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 28-bit UMTS Cell Identity
+     * @param psc 9-bit UMTS Primary Scrambling Code
+     *
+     * @hide
+     */
+    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
+        mMcc = mcc;
+        mMnc = mnc;
+        mLac = lac;
+        mCid = cid;
+        mPsc = psc;
+    }
+
+    private CellIdentityWcdma(CellIdentityWcdma cid) {
+        mMcc = cid.mMcc;
+        mMnc = cid.mMnc;
+        mLac = cid.mLac;
+        mCid = cid.mCid;
+        mPsc = cid.mPsc;
+    }
+
+    CellIdentityWcdma copy() {
+       return new CellIdentityWcdma(this);
+    }
+
+    /**
+     * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown
+     */
+    public int getMcc() {
+        return mMcc;
+    }
+
+    /**
+     * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown
+     */
+    public int getMnc() {
+        return mMnc;
+    }
+
+    /**
+     * @return 16-bit Location Area Code, 0..65535, Integer.MAX_VALUE if unknown
+     */
+    public int getLac() {
+        return mLac;
+    }
+
+    /**
+     * @return CID
+     * 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, Integer.MAX_VALUE if unknown
+     */
+    public int getCid() {
+        return mCid;
+    }
+
+    /**
+     * @return 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511, Integer.MAX_VALUE
+     * if unknown
+     */
+    public int getPsc() {
+        return mPsc;
+    }
+
+    @Override
+    public int hashCode() {
+        int primeNum = 31;
+        return (mMcc * primeNum) + (mMnc * primeNum) + (mLac * primeNum) + (mCid * primeNum) +
+                (mPsc * primeNum);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (super.equals(other)) {
+            try {
+                CellIdentityWcdma o = (CellIdentityWcdma)other;
+                return mMcc == o.mMcc &&
+                        mMnc == o.mMnc &&
+                        mLac == o.mLac &&
+                        mCid == o.mCid &&
+                        mPsc == o.mPsc;
+            } catch (ClassCastException e) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("CellIdentityWcdma:{");
+        sb.append(" mMcc=").append(mMcc);
+        sb.append(" mMnc=").append(mMnc);
+        sb.append(" mLac=").append(mLac);
+        sb.append(" mCid=").append(mCid);
+        sb.append(" mPsc=").append(mPsc);
+        sb.append("}");
+
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        dest.writeInt(mMcc);
+        dest.writeInt(mMnc);
+        dest.writeInt(mLac);
+        dest.writeInt(mCid);
+        dest.writeInt(mPsc);
+    }
+
+    /** Construct from Parcel, type has already been processed */
+    private CellIdentityWcdma(Parcel in) {
+        mMcc = in.readInt();
+        mMnc = in.readInt();
+        mLac = in.readInt();
+        mCid = in.readInt();
+        mPsc = in.readInt();
+        if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
+    }
+
+    /** Implement the Parcelable interface */
+    @SuppressWarnings("hiding")
+    public static final Creator<CellIdentityWcdma> CREATOR =
+            new Creator<CellIdentityWcdma>() {
+        @Override
+        public CellIdentityWcdma createFromParcel(Parcel in) {
+            return new CellIdentityWcdma(in);
+        }
+
+        @Override
+        public CellIdentityWcdma[] newArray(int size) {
+            return new CellIdentityWcdma[size];
+        }
+    };
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index fe3c68b..bfa0942 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -31,6 +31,8 @@
     protected static final int TYPE_CDMA = 2;
     /** @hide */
     protected static final int TYPE_LTE = 3;
+    /** @hide */
+    protected static final int TYPE_WCDMA = 4;
 
     // Type to distinguish where time stamp gets recorded.
 
@@ -201,6 +203,7 @@
                     case TYPE_GSM: return CellInfoGsm.createFromParcelBody(in);
                     case TYPE_CDMA: return CellInfoCdma.createFromParcelBody(in);
                     case TYPE_LTE: return CellInfoLte.createFromParcelBody(in);
+                    case TYPE_WCDMA: return CellInfoWcdma.createFromParcelBody(in);
                     default: throw new RuntimeException("Bad CellInfo Parcel");
                 }
         }
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
new file mode 100644
index 0000000..0615702
--- /dev/null
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Immutable cell information from a point in time.
+ */
+public final class CellInfoWcdma extends CellInfo implements Parcelable {
+
+    private static final String LOG_TAG = "CellInfoWcdma";
+    private static final boolean DBG = false;
+
+    private CellIdentityWcdma mCellIdentityWcdma;
+    private CellSignalStrengthWcdma mCellSignalStrengthWcdma;
+
+    /** @hide */
+    public CellInfoWcdma() {
+        super();
+        mCellIdentityWcdma = new CellIdentityWcdma();
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma();
+    }
+
+    /** @hide */
+    public CellInfoWcdma(CellInfoWcdma ci) {
+        super(ci);
+        this.mCellIdentityWcdma = ci.mCellIdentityWcdma.copy();
+        this.mCellSignalStrengthWcdma = ci.mCellSignalStrengthWcdma.copy();
+    }
+
+    public CellIdentityWcdma getCellIdentity() {
+        return mCellIdentityWcdma;
+    }
+    /** @hide */
+    public void setCellIdentity(CellIdentityWcdma cid) {
+        mCellIdentityWcdma = cid;
+    }
+
+    public CellSignalStrengthWcdma getCellSignalStrength() {
+        return mCellSignalStrengthWcdma;
+    }
+    /** @hide */
+    public void setCellSignalStrength(CellSignalStrengthWcdma css) {
+        mCellSignalStrengthWcdma = css;
+    }
+
+    /**
+     * @return hash code
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + mCellIdentityWcdma.hashCode() + mCellSignalStrengthWcdma.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!super.equals(other)) {
+            return false;
+        }
+        try {
+            CellInfoWcdma o = (CellInfoWcdma) other;
+            return mCellIdentityWcdma.equals(o.mCellIdentityWcdma)
+                    && mCellSignalStrengthWcdma.equals(o.mCellSignalStrengthWcdma);
+        } catch (ClassCastException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("CellInfoWcdma:{");
+        sb.append(super.toString());
+        sb.append(" ").append(mCellIdentityWcdma);
+        sb.append(" ").append(mCellSignalStrengthWcdma);
+        sb.append("}");
+
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags, TYPE_WCDMA);
+        mCellIdentityWcdma.writeToParcel(dest, flags);
+        mCellSignalStrengthWcdma.writeToParcel(dest, flags);
+    }
+
+    /**
+     * Construct a CellInfoWcdma object from the given parcel
+     * where the token is already been processed.
+     */
+    private CellInfoWcdma(Parcel in) {
+        super(in);
+        mCellIdentityWcdma = CellIdentityWcdma.CREATOR.createFromParcel(in);
+        mCellSignalStrengthWcdma = CellSignalStrengthWcdma.CREATOR.createFromParcel(in);
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<CellInfoWcdma> CREATOR = new Creator<CellInfoWcdma>() {
+        @Override
+        public CellInfoWcdma createFromParcel(Parcel in) {
+            in.readInt(); // Skip past token, we know what it is
+            return createFromParcelBody(in);
+        }
+
+        @Override
+        public CellInfoWcdma[] newArray(int size) {
+            return new CellInfoWcdma[size];
+        }
+    };
+
+    /** @hide */
+    protected static CellInfoWcdma createFromParcelBody(Parcel in) {
+        return new CellInfoWcdma(in);
+    }
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 2c36344..d27fcec 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -21,7 +21,7 @@
 import android.telephony.Rlog;
 
 /**
- * LTE signal strength related information.
+ * GSM signal strength related information.
  */
 public final class CellSignalStrengthGsm extends CellSignalStrength implements Parcelable {
 
@@ -30,7 +30,7 @@
 
     private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
     private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
-    private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8;
+    private static final int GSM_SIGNAL_STRENGTH_MODERATE = 5;
 
     private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
@@ -67,7 +67,8 @@
     /**
      * Initialize all the values
      *
-     * @param SignalStrength
+     * @param ss SignalStrength as ASU value
+     * @param ber is Bit Error Rate
      *
      * @hide
      */
@@ -139,7 +140,7 @@
     }
 
     /**
-     * Get the LTE signal level as an asu value between 0..97, 99 is unknown
+     * Get the signal level as an asu value between 0..31, 99 is unknown
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      */
     @Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
new file mode 100644
index 0000000..b94b01d
--- /dev/null
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Wcdma signal strength related information.
+ */
+public final class CellSignalStrengthWcdma extends CellSignalStrength implements Parcelable {
+
+    private static final String LOG_TAG = "CellSignalStrengthWcdma";
+    private static final boolean DBG = false;
+
+    private static final int WCDMA_SIGNAL_STRENGTH_GREAT = 12;
+    private static final int WCDMA_SIGNAL_STRENGTH_GOOD = 8;
+    private static final int WCDMA_SIGNAL_STRENGTH_MODERATE = 5;
+
+    private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
+    private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+
+    /**
+     * Empty constructor
+     *
+     * @hide
+     */
+    public CellSignalStrengthWcdma() {
+        setDefaultValues();
+    }
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public CellSignalStrengthWcdma(int ss, int ber) {
+        initialize(ss, ber);
+    }
+
+    /**
+     * Copy constructors
+     *
+     * @param s Source SignalStrength
+     *
+     * @hide
+     */
+    public CellSignalStrengthWcdma(CellSignalStrengthWcdma s) {
+        copyFrom(s);
+    }
+
+    /**
+     * Initialize all the values
+     *
+     * @param ss SignalStrength as ASU value
+     * @param ber is Bit Error Rate
+     *
+     * @hide
+     */
+    public void initialize(int ss, int ber) {
+        mSignalStrength = ss;
+        mBitErrorRate = ber;
+    }
+
+    /**
+     * @hide
+     */
+    protected void copyFrom(CellSignalStrengthWcdma s) {
+        mSignalStrength = s.mSignalStrength;
+        mBitErrorRate = s.mBitErrorRate;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public CellSignalStrengthWcdma copy() {
+        return new CellSignalStrengthWcdma(this);
+    }
+
+    /** @hide */
+    @Override
+    public void setDefaultValues() {
+        mSignalStrength = Integer.MAX_VALUE;
+        mBitErrorRate = Integer.MAX_VALUE;
+    }
+
+    /**
+     * Get signal level as an int from 0..4
+     */
+    @Override
+    public int getLevel() {
+        int level;
+
+        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+        // asu = 0 (-113dB or less) is very weak
+        // signal, its better to show 0 bars to the user in such cases.
+        // asu = 99 is a special case, where the signal strength is unknown.
+        int asu = mSignalStrength;
+        if (asu <= 2 || asu == 99) level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (asu >= WCDMA_SIGNAL_STRENGTH_GREAT) level = SIGNAL_STRENGTH_GREAT;
+        else if (asu >= WCDMA_SIGNAL_STRENGTH_GOOD)  level = SIGNAL_STRENGTH_GOOD;
+        else if (asu >= WCDMA_SIGNAL_STRENGTH_MODERATE)  level = SIGNAL_STRENGTH_MODERATE;
+        else level = SIGNAL_STRENGTH_POOR;
+        if (DBG) log("getLevel=" + level);
+        return level;
+    }
+
+    /**
+     * Get the signal strength as dBm
+     */
+    @Override
+    public int getDbm() {
+        int dBm;
+
+        int level = mSignalStrength;
+        int asu = (level == 99 ? Integer.MAX_VALUE : level);
+        if (asu != Integer.MAX_VALUE) {
+            dBm = -113 + (2 * asu);
+        } else {
+            dBm = Integer.MAX_VALUE;
+        }
+        if (DBG) log("getDbm=" + dBm);
+        return dBm;
+    }
+
+    /**
+     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     */
+    @Override
+    public int getAsuLevel() {
+        // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+        // asu = 0 (-113dB or less) is very weak
+        // signal, its better to show 0 bars to the user in such cases.
+        // asu = 99 is a special case, where the signal strength is unknown.
+        int level = mSignalStrength;
+        if (DBG) log("getAsuLevel=" + level);
+        return level;
+    }
+
+    @Override
+    public int hashCode() {
+        int primeNum = 31;
+        return (mSignalStrength * primeNum) + (mBitErrorRate * primeNum);
+    }
+
+    @Override
+    public boolean equals (Object o) {
+        CellSignalStrengthWcdma s;
+
+        try {
+            s = (CellSignalStrengthWcdma) o;
+        } catch (ClassCastException ex) {
+            return false;
+        }
+
+        if (o == null) {
+            return false;
+        }
+
+        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate;
+    }
+
+    /**
+     * @return string representation.
+     */
+    @Override
+    public String toString() {
+        return "CellSignalStrengthWcdma:"
+                + " ss=" + mSignalStrength
+                + " ber=" + mBitErrorRate;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (DBG) log("writeToParcel(Parcel, int): " + toString());
+        dest.writeInt(mSignalStrength);
+        dest.writeInt(mBitErrorRate);
+    }
+
+    /**
+     * Construct a SignalStrength object from the given parcel
+     * where the token is already been processed.
+     */
+    private CellSignalStrengthWcdma(Parcel in) {
+        mSignalStrength = in.readInt();
+        mBitErrorRate = in.readInt();
+        if (DBG) log("CellSignalStrengthWcdma(Parcel): " + toString());
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @SuppressWarnings("hiding")
+    public static final Parcelable.Creator<CellSignalStrengthWcdma> CREATOR =
+            new Parcelable.Creator<CellSignalStrengthWcdma>() {
+        @Override
+        public CellSignalStrengthWcdma createFromParcel(Parcel in) {
+            return new CellSignalStrengthWcdma(in);
+        }
+
+        @Override
+        public CellSignalStrengthWcdma[] newArray(int size) {
+            return new CellSignalStrengthWcdma[size];
+        }
+    };
+
+    /**
+     * log
+     */
+    private static void log(String s) {
+        Rlog.w(LOG_TAG, s);
+    }
+}
diff --git a/tests/CanvasCompare/AndroidManifest.xml b/tests/CanvasCompare/AndroidManifest.xml
index 1cb8c37..b55e290 100644
--- a/tests/CanvasCompare/AndroidManifest.xml
+++ b/tests/CanvasCompare/AndroidManifest.xml
@@ -15,8 +15,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.test.hwuicompare" >
 
-    <!-- for perfhud -->
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application
         android:label="@string/app_name"
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
index e0ff1dc..1ed4723 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/AutomaticActivity.java
@@ -16,11 +16,20 @@
 
 package com.android.test.hwuicompare;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.TreeSet;
 
-import com.android.test.hwuicompare.R;
+import org.json.JSONException;
+import org.json.JSONObject;
 
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.Trace;
 import android.util.Log;
 import android.widget.ImageView;
@@ -31,20 +40,31 @@
     private static final float ERROR_DISPLAY_THRESHOLD = 0.01f;
     protected static final boolean DRAW_BITMAPS = false;
 
+    /**
+     * Threshold of error change required to consider a test regressed/improved
+     */
+    private static final float ERROR_CHANGE_THRESHOLD = 0.001f;
+
+    private static final float[] ERROR_CUTOFFS = {
+            0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f
+    };
+
+    private final float[] mErrorRates = new float[ERROR_CUTOFFS.length];
+    private float mTotalTests = 0;
+    private float mTotalError = 0;
+    private int mTestsRegressed = 0;
+    private int mTestsImproved = 0;
+
     private ImageView mSoftwareImageView = null;
     private ImageView mHardwareImageView = null;
 
-    private static final float[] ERROR_CUTOFFS = {0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f};
-    private float[] mErrorRates = new float[ERROR_CUTOFFS.length];
-    private float mTotalTests = 0;
-    private float mTotalError = 0;
 
-    public abstract static class TestCallback {
+    public abstract static class FinalCallback {
         abstract void report(String name, float value);
-        void complete() {}
+        void complete() {};
     }
 
-    private ArrayList<TestCallback> mTestCallbacks = new ArrayList<TestCallback>();
+    private final ArrayList<FinalCallback> mFinalCallbacks = new ArrayList<FinalCallback>();
 
     Runnable mRunnable = new Runnable() {
         @Override
@@ -64,32 +84,11 @@
             float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
             Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
 
-            if (error > ERROR_DISPLAY_THRESHOLD) {
-                String modname = "";
-                for (String s : DisplayModifier.getLastAppliedModifications()) {
-                    modname = modname.concat(s + ".");
-                }
-                Log.d(LOG_TAG, String.format("error for %s was %2.9f", modname, error));
-            }
-            for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
-                if (error <= ERROR_CUTOFFS[i]) break;
-                mErrorRates[i]++;
-            }
-            mTotalError += error;
-            mTotalTests++;
+            final String[] modifierNames = DisplayModifier.getLastAppliedModifications();
+            handleError(modifierNames, error);
 
             if (DisplayModifier.step()) {
-                for (TestCallback c : mTestCallbacks) {
-                    c.report("averageError", (mTotalError / mTotalTests));
-                    for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
-                        c.report(String.format("error over %1.3f", ERROR_CUTOFFS[i]),
-                                mErrorRates[i]/mTotalTests);
-                    }
-                    c.complete();
-                }
-
-                Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
-                finish();
+                finishTest();
             } else {
                 mHardwareView.invalidate();
                 if (DRAW_BITMAPS) {
@@ -116,11 +115,186 @@
         mHardwareImageView = (ImageView) findViewById(R.id.hardware_image_view);
 
         onCreateCommon(mRunnable);
-        mTestCallbacks.add(new TestCallback() {
+        beginTest();
+    }
+
+    private static class TestResult {
+        TestResult(String label, float error) {
+            mLabel = label;
+            mTotalError = error;
+            mCount = 1;
+        }
+        public void addInto(float error) {
+            mTotalError += error;
+            mCount++;
+        }
+        public float getAverage() {
+            return mTotalError / mCount;
+        }
+        final String mLabel;
+        float mTotalError;
+        int mCount;
+    }
+
+    JSONObject mOutputJson = null;
+    JSONObject mInputJson = null;
+    final HashMap<String, TestResult> mModifierResults = new HashMap<String, TestResult>();
+    final HashMap<String, TestResult> mIndividualResults = new HashMap<String, TestResult>();
+    final HashMap<String, TestResult> mModifierDiffResults = new HashMap<String, TestResult>();
+    final HashMap<String, TestResult> mIndividualDiffResults = new HashMap<String, TestResult>();
+    private void beginTest() {
+        mFinalCallbacks.add(new FinalCallback() {
+            @Override
             void report(String name, float value) {
                 Log.d(LOG_TAG, name + " " + value);
             };
         });
+
+        File inputFile = new File(Environment.getExternalStorageDirectory(),
+                "CanvasCompareInput.json");
+        if (inputFile.exists() && inputFile.canRead() && inputFile.length() > 0) {
+            try {
+                FileInputStream inputStream = new FileInputStream(inputFile);
+                Log.d(LOG_TAG, "Parsing input file...");
+                StringBuffer content = new StringBuffer((int)inputFile.length());
+                byte[] buffer = new byte[1024];
+                while (inputStream.read(buffer) != -1) {
+                    content.append(new String(buffer));
+                }
+                mInputJson = new JSONObject(content.toString());
+                inputStream.close();
+                Log.d(LOG_TAG, "Parsed input file with " + mInputJson.length() + " entries");
+            } catch (JSONException e) {
+                Log.e(LOG_TAG, "error parsing input json", e);
+            } catch (IOException e) {
+                Log.e(LOG_TAG, "error reading input json from sd", e);
+            }
+        }
+
+        mOutputJson = new JSONObject();
+    }
+
+    private static void logTestResultHash(String label, HashMap<String, TestResult> map) {
+        Log.d(LOG_TAG, "---------------");
+        Log.d(LOG_TAG, label + ":");
+        Log.d(LOG_TAG, "---------------");
+        TreeSet<TestResult> set = new TreeSet<TestResult>(new Comparator<TestResult>() {
+            @Override
+            public int compare(TestResult lhs, TestResult rhs) {
+                if (lhs == rhs) return 0; // don't need to worry about complex equality
+
+                int cmp = Float.compare(lhs.getAverage(), rhs.getAverage());
+                if (cmp != 0) {
+                    return cmp;
+                }
+                return lhs.mLabel.compareTo(rhs.mLabel);
+            }
+        });
+
+        for (TestResult t : map.values()) {
+            set.add(t);
+        }
+
+        for (TestResult t : set.descendingSet()) {
+            if (Math.abs(t.getAverage()) > ERROR_DISPLAY_THRESHOLD) {
+                Log.d(LOG_TAG, String.format("%2.4f : %s", t.getAverage(), t.mLabel));
+            }
+        }
+        Log.d(LOG_TAG, "");
+    }
+
+    private void finishTest() {
+        for (FinalCallback c : mFinalCallbacks) {
+            c.report("averageError", (mTotalError / mTotalTests));
+            for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
+                c.report(String.format("tests with error over %1.3f", ERROR_CUTOFFS[i]),
+                        mErrorRates[i]);
+            }
+            if (mInputJson != null) {
+                c.report("tests regressed", mTestsRegressed);
+                c.report("tests improved", mTestsImproved);
+            }
+            c.complete();
+        }
+
+        try {
+            if (mOutputJson != null) {
+                String outputString = mOutputJson.toString(4);
+                File outputFile = new File(Environment.getExternalStorageDirectory(),
+                        "CanvasCompareOutput.json");
+                FileOutputStream outputStream = new FileOutputStream(outputFile);
+                outputStream.write(outputString.getBytes());
+                outputStream.close();
+                Log.d(LOG_TAG, "Saved output file with " + mOutputJson.length() + " entries");
+            }
+        } catch (JSONException e) {
+            Log.e(LOG_TAG, "error during JSON stringify", e);
+        } catch (IOException e) {
+            Log.e(LOG_TAG, "error storing JSON output on sd", e);
+        }
+
+        logTestResultHash("Modifier change vs previous", mModifierDiffResults);
+        logTestResultHash("Invidual test change vs previous", mIndividualDiffResults);
+        logTestResultHash("Modifier average test results", mModifierResults);
+        logTestResultHash("Individual test results", mIndividualResults);
+
+        Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
+        finish();
+    }
+
+    /**
+     * Inserts the error value into all TestResult objects, associated with each of its modifiers
+     */
+    private static void addForAllModifiers(String fullName, float error, String[] modifierNames,
+            HashMap<String, TestResult> modifierResults) {
+        for (String modifierName : modifierNames) {
+            TestResult r = modifierResults.get(fullName);
+            if (r == null) {
+                modifierResults.put(modifierName, new TestResult(modifierName, error));
+            } else {
+                r.addInto(error);
+            }
+        }
+    }
+
+    private void handleError(final String[] modifierNames, final float error) {
+        String fullName = "";
+        for (String s : modifierNames) {
+            fullName = fullName.concat("." + s);
+        }
+        fullName = fullName.substring(1);
+
+        float deltaError = 0;
+        if (mInputJson != null) {
+            try {
+                deltaError = error - (float)mInputJson.getDouble(fullName);
+            } catch (JSONException e) {
+                Log.w(LOG_TAG, "Warning: unable to read from input json", e);
+            }
+            if (deltaError > ERROR_CHANGE_THRESHOLD) mTestsRegressed++;
+            if (deltaError < -ERROR_CHANGE_THRESHOLD) mTestsImproved++;
+            mIndividualDiffResults.put(fullName, new TestResult(fullName, deltaError));
+            addForAllModifiers(fullName, deltaError, modifierNames, mModifierDiffResults);
+        }
+
+        mIndividualResults.put(fullName, new TestResult(fullName, error));
+        addForAllModifiers(fullName, error, modifierNames, mModifierResults);
+
+        try {
+            if (mOutputJson != null) {
+                mOutputJson.put(fullName, error);
+            }
+        } catch (JSONException e) {
+            Log.e(LOG_TAG, "exception during JSON recording", e);
+            mOutputJson = null;
+        }
+
+        for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
+            if (error <= ERROR_CUTOFFS[i]) break;
+            mErrorRates[i]++;
+        }
+        mTotalError += error;
+        mTotalTests++;
     }
 
     @Override
@@ -130,7 +304,7 @@
     }
 
     // FOR TESTING
-    public void setCallback(TestCallback c) {
-        mTestCallbacks.add(c);
+    public void setFinalCallback(FinalCallback c) {
+        mFinalCallbacks.add(c);
     }
 }
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
index 6ea8237..1ff153c 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/Test.java
@@ -1,6 +1,6 @@
 package com.android.test.hwuicompare;
 
-import com.android.test.hwuicompare.AutomaticActivity.TestCallback;
+import com.android.test.hwuicompare.AutomaticActivity.FinalCallback;
 
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
@@ -18,7 +18,7 @@
         super.setUp();
         mBundle = new Bundle();
         mActivity = getActivity();
-        mActivity.setCallback(new TestCallback() {
+        mActivity.setFinalCallback(new FinalCallback() {
 
             @Override
             void report(String key, float value) {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index f093b52..547ae95 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -71,7 +71,7 @@
 
     DhcpInfo getDhcpInfo();
 
-    boolean isScanningAlwaysAvailable();
+    boolean isScanAlwaysAvailable();
 
     boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws);
 
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 4e7497c..6e3034b 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -223,6 +223,9 @@
         public static final int PWD     = 3;
         /** @hide */
         public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD" };
+
+        /** Prevent initialization */
+        private Eap() {}
     }
 
     /** The inner authentication method used */
@@ -239,6 +242,9 @@
         private static final String PREFIX = "auth=";
         /** @hide */
         public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" };
+
+        /** Prevent initialization */
+        private Phase2() {}
     }
 
     /** Internal use only */
@@ -363,6 +369,16 @@
     }
 
     /**
+     * Get the password.
+     *
+     * Returns locally set password value. For networks fetched from
+     * framework, returns "*".
+     */
+    public String getPassword() {
+        return getFieldValue(PASSWORD_KEY, "");
+    }
+
+    /**
      * Set CA certificate alias.
      *
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -396,14 +412,27 @@
      * @throws IllegalArgumentException if not a CA certificate
      */
     public void setCaCertificate(X509Certificate cert) {
-        if (cert.getBasicConstraints() >= 0) {
-            mCaCert = cert;
+        if (cert != null) {
+            if (cert.getBasicConstraints() >= 0) {
+                mCaCert = cert;
+            } else {
+                throw new IllegalArgumentException("Not a CA certificate");
+            }
         } else {
-            throw new IllegalArgumentException("Not a CA certificate");
+            mCaCert = null;
         }
     }
 
     /**
+     * Get CA certificate
+     *
+     * @return X.509 CA certificate
+     */
+    public X509Certificate getCaCertificate() {
+        return mCaCert;
+    }
+
+    /**
      * Set Client certificate alias.
      *
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -463,6 +492,15 @@
         mClientCertificate = clientCertificate;
     }
 
+    /**
+     * Get client certificate
+     *
+     * @return X.509 client certificate
+     */
+    public X509Certificate getClientCertificate() {
+        return mClientCertificate;
+    }
+
     boolean needsKeyStore() {
         // Has no keys to be installed
         if (mClientCertificate == null && mCaCert == null) return false;
@@ -645,6 +683,7 @@
     }
 
     private String removeDoubleQuotes(String string) {
+        if (TextUtils.isEmpty(string)) return "";
         int length = string.length();
         if ((length > 1) && (string.charAt(0) == '"')
                 && (string.charAt(length - 1) == '"')) {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0c0a144..a7a5924 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -794,9 +794,9 @@
      *
      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
      */
-    public boolean isScanningAlwaysAvailable() {
+    public boolean isScanAlwaysAvailable() {
         try {
-            return mService.isScanningAlwaysAvailable();
+            return mService.isScanAlwaysAvailable();
         } catch (RemoteException e) {
             return false;
         }